home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / OldSrc / CH4 / SRC / WARPFORM.FRM (.txt) < prev    next >
Encoding:
Visual Basic Form  |  1996-05-01  |  24.7 KB  |  816 lines

  1. VERSION 4.00
  2. Begin VB.Form WarpForm 
  3.    Caption         =   "Warp"
  4.    ClientHeight    =   4560
  5.    ClientLeft      =   735
  6.    ClientTop       =   1065
  7.    ClientWidth     =   8235
  8.    Height          =   5250
  9.    Left            =   675
  10.    LinkTopic       =   "Form1"
  11.    ScaleHeight     =   304
  12.    ScaleMode       =   3  'Pixel
  13.    ScaleWidth      =   549
  14.    Top             =   435
  15.    Width           =   8355
  16.    Begin VB.CommandButton CmdWarp 
  17.       Caption         =   "Warp"
  18.       Enabled         =   0   'False
  19.       Height          =   375
  20.       Left            =   1320
  21.       TabIndex        =   3
  22.       Top             =   4125
  23.       Width           =   855
  24.    End
  25.    Begin VB.ComboBox WarpCombo 
  26.       Height          =   315
  27.       ItemData        =   "WARPFORM.frx":0000
  28.       Left            =   720
  29.       List            =   "WARPFORM.frx":0010
  30.       Sorted          =   -1  'True
  31.       Style           =   2  'Dropdown List
  32.       TabIndex        =   2
  33.       Top             =   3720
  34.       Width           =   2175
  35.    End
  36.    Begin VB.PictureBox ToPict 
  37.       AutoRedraw      =   -1  'True
  38.       BackColor       =   &H00C0C0C0&
  39.       Height          =   4560
  40.       Left            =   3660
  41.       Picture         =   "WARPFORM.frx":0032
  42.       ScaleHeight     =   300
  43.       ScaleMode       =   3  'Pixel
  44.       ScaleWidth      =   300
  45.       TabIndex        =   1
  46.       Top             =   0
  47.       Width           =   4560
  48.    End
  49.    Begin VB.PictureBox FromPict 
  50.       AutoRedraw      =   -1  'True
  51.       BackColor       =   &H00C0C0C0&
  52.       Height          =   3615
  53.       Left            =   0
  54.       Picture         =   "WARPFORM.frx":0478
  55.       ScaleHeight     =   237
  56.       ScaleMode       =   3  'Pixel
  57.       ScaleWidth      =   237
  58.       TabIndex        =   0
  59.       Top             =   0
  60.       Width           =   3615
  61.    End
  62.    Begin MSComDlg.CommonDialog FileDialog 
  63.       Left            =   3000
  64.       Top             =   3840
  65.       _version        =   65536
  66.       _extentx        =   847
  67.       _extenty        =   847
  68.       _stockprops     =   0
  69.       cancelerror     =   -1  'True
  70.    End
  71.    Begin VB.Menu mnuFile 
  72.       Caption         =   "&File"
  73.       Begin VB.Menu mnuFileLoad 
  74.          Caption         =   "&Load..."
  75.          Shortcut        =   ^L
  76.       End
  77.       Begin VB.Menu mnuFileSep 
  78.          Caption         =   "-"
  79.       End
  80.       Begin VB.Menu mnuFileExit 
  81.          Caption         =   "E&xit"
  82.       End
  83.    End
  84. Attribute VB_Name = "WarpForm"
  85. Attribute VB_Creatable = False
  86. Attribute VB_Exposed = False
  87. Option Explicit
  88. Dim SysPalSize As Integer
  89. Dim NumStaticColors As Integer
  90. Dim StaticColor1 As Integer
  91. Dim StaticColor2 As Integer
  92. Dim LogPal As Integer
  93. Dim palentry(0 To 255) As PALETTEENTRY
  94. Dim wid As Long
  95. Dim hgt As Long
  96. Dim bytes() As Byte
  97. ' ************************************************
  98. ' Return the arc tangent of y/x taking into
  99. ' account the proper quadrant.
  100. ' ************************************************
  101. Function Arctan2(x As Single, y As Single)
  102. Const PI = 3.14159
  103. Const PI_OVER_2 = PI / 2
  104. Dim theta As Single
  105.     If x = 0 Then
  106.         If y > 0 Then
  107.             Arctan2 = PI_OVER_2
  108.         Else
  109.             Arctan2 = -PI_OVER_2
  110.         End If
  111.     Else
  112.         theta = Atn(y / x)
  113.         If x < 0 Then theta = PI + theta
  114.         Arctan2 = theta
  115.     End If
  116. End Function
  117. ' ************************************************
  118. ' Draw the warped image.
  119. ' ************************************************
  120. Sub DrawImage()
  121. Dim x2 As Integer
  122. Dim y2 As Integer
  123. Dim idx As Integer
  124.     ToPict.Cls
  125.     x2 = FromPict.ScaleWidth - 1
  126.     y2 = FromPict.ScaleHeight - 1
  127.     ' See which kind of warping the user wants.
  128.     idx = WarpCombo.ListIndex
  129.     If idx < 0 Then
  130.         Beep
  131.         Exit Sub
  132.     End If
  133.     Select Case WarpCombo.List(idx)
  134.         Case "Wave"
  135.             WavePicture FromPict, ToPict, _
  136.                 0, 0, x2, y2
  137.         
  138.         Case "Twist"
  139.             TwistPicture FromPict, ToPict, _
  140.                 0, 0, x2, y2
  141.         
  142.         Case "Fisheye"
  143.             FisheyePicture FromPict, ToPict, _
  144.                 0, 0, x2, y2
  145.         
  146.         Case "Narrow"
  147.             NarrowPicture FromPict, ToPict, _
  148.                 0, 0, x2, y2
  149.         
  150.         Case Else
  151.             Beep
  152.             Exit Sub
  153.     End Select
  154. End Sub
  155. ' ************************************************
  156. ' Narrow X towards the top.
  157. ' ************************************************
  158. Sub NarrowPicture( _
  159.     ByVal from_pic As Control, ByVal to_pic As Control, _
  160.     ByVal fx1 As Integer, ByVal fy1 As Integer, _
  161.     ByVal fx2 As Integer, ByVal fy2 As Integer)
  162. Const MIN_FACT = 0.3
  163. Dim bm As BITMAP
  164. Dim hbm As Integer
  165. Dim status As Long
  166. Dim from_bytes() As Byte
  167. Dim to_bytes() As Byte
  168. Dim from_wid As Long
  169. Dim from_hgt As Long
  170. Dim to_wid As Long
  171. Dim to_hgt As Long
  172. Dim tx1 As Single
  173. Dim tx2 As Single
  174. Dim ty1 As Single
  175. Dim ty2 As Single
  176. Dim fx As Single
  177. Dim fy As Single
  178. Dim tx As Single
  179. Dim ty As Single
  180. Dim fxmid As Single
  181. Dim txmid As Single
  182. Dim x As Single
  183. Dim y As Single
  184. Dim ifx As Integer
  185. Dim ify As Integer
  186. Dim dx As Single
  187. Dim dy As Single
  188. Dim fact As Single
  189. Dim dfact As Single
  190. Dim c1 As Integer
  191. Dim c2 As Integer
  192. Dim c3 As Integer
  193. Dim c4 As Integer
  194. Dim i1 As Integer
  195. Dim i2 As Integer
  196. Dim clr As Integer
  197.     ' Get from_pic's pixels.
  198.     hbm = from_pic.Image
  199.     status = GetObject(hbm, 14, bm)
  200.     from_wid = bm.bmWidthBytes
  201.     from_hgt = bm.bmHeight
  202.     ReDim from_bytes(0 To from_wid - 1, 0 To from_hgt - 1)
  203.     status = GetBitmapBits(hbm, from_wid * from_hgt, from_bytes(0, 0))
  204.     ' Get to_pic's pixels.
  205.     hbm = to_pic.Image
  206.     status = GetObject(hbm, 14, bm)
  207.     to_wid = bm.bmWidthBytes
  208.     to_hgt = bm.bmHeight
  209.     ReDim to_bytes(0 To to_wid - 1, 0 To to_hgt - 1)
  210.     status = GetBitmapBits(hbm, to_wid * to_hgt, to_bytes(0, 0))
  211.         
  212.     ' Set the bounds for to_pic.
  213.     tx1 = fx1
  214.     tx2 = fx2
  215.     ty1 = fy1
  216.     ty2 = fy2
  217.     txmid = (tx1 + tx2) / 2
  218.     fxmid = (fx1 + fx2) / 2
  219.     ' Perform the transformation.
  220.     fact = MIN_FACT
  221.     dfact = (1 - MIN_FACT) / (ty2 - ty1)
  222.     For ty = ty1 To ty2
  223.         For tx = tx1 To tx2
  224.             ' See where the point came from.
  225.             dx = tx - txmid
  226.             fx = dx / fact + fxmid
  227.             fy = ty
  228.             
  229.             ' Skip it if any of the four nearest
  230.             ' source pixels lie outside the allowed
  231.             ' source area.
  232.             ify = Int(fy)
  233.             ifx = Int(fx)
  234.             If ifx >= fx1 And ifx < fx2 And _
  235.                ify >= fy1 And ify < fy2 Then
  236.                 ' Interpolate using the four nearest
  237.                 ' pixels in from_pic.
  238.                 dy = fy - ify
  239.                 dx = fx - ifx
  240.                 c1 = palentry(from_bytes(ifx, ify)).peRed
  241.                 c2 = palentry(from_bytes(ifx + 1, ify)).peRed
  242.                 c3 = palentry(from_bytes(ifx, ify + 1)).peRed
  243.                 c4 = palentry(from_bytes(ifx + 1, ify + 1)).peRed
  244.                 ' Interpolate in the Y direction.
  245.                 i1 = c1 * (1 - dy) + c3 * dy
  246.                 i2 = c2 * (1 - dy) + c4 * dy
  247.                 ' Interpolate the results in the X direction.
  248.                 clr = i1 * (1 - dx) + i2 * dx
  249.                 to_bytes(tx, ty) = NearestNonstaticGray(clr)
  250.             End If
  251.         Next tx
  252.         fact = fact + dfact
  253.     Next ty
  254.     ' Update from_pic.
  255.     status = SetBitmapBits(hbm, to_wid * to_hgt, to_bytes(0, 0))
  256.     to_pic.Refresh
  257. End Sub
  258. ' ************************************************
  259. ' Warp using:
  260. '   x' = r * Cos(theta + r / K - OFFSET)
  261. '   y' = r * Sin(theta + r / K - OFFSET)
  262. ' The inverse transformation is:
  263. '   r = Sqr(x' * x' + y' * y')
  264. '   theta = Atn(x' / y')
  265. ' All of this with origin at the center of the
  266. ' input and output areas.
  267. ' ************************************************
  268. Sub TwistPicture( _
  269.     ByVal from_pic As Control, ByVal to_pic As Control, _
  270.     ByVal fx1 As Integer, ByVal fy1 As Integer, _
  271.     ByVal fx2 As Integer, ByVal fy2 As Integer)
  272. Const PI = 3.14159
  273. Const PI_OVER_2 = PI / 2
  274. Const K = 100
  275. Const OFFSET = -PI_OVER_2
  276. Dim bm As BITMAP
  277. Dim hbm As Integer
  278. Dim status As Long
  279. Dim from_bytes() As Byte
  280. Dim to_bytes() As Byte
  281. Dim from_wid As Long
  282. Dim from_hgt As Long
  283. Dim to_wid As Long
  284. Dim to_hgt As Long
  285. Dim tx1 As Single
  286. Dim tx2 As Single
  287. Dim ty1 As Single
  288. Dim ty2 As Single
  289. Dim fx As Single
  290. Dim fy As Single
  291. Dim tx As Single
  292. Dim ty As Single
  293. Dim fxmid As Single
  294. Dim fymid As Single
  295. Dim txmid As Single
  296. Dim tymid As Single
  297. Dim x As Single
  298. Dim y As Single
  299. Dim ifx As Integer
  300. Dim ify As Integer
  301. Dim dx As Single
  302. Dim dy As Single
  303. Dim r As Single
  304. Dim arctan As Single
  305. Dim theta As Single
  306. Dim c1 As Integer
  307. Dim c2 As Integer
  308. Dim c3 As Integer
  309. Dim c4 As Integer
  310. Dim i1 As Integer
  311. Dim i2 As Integer
  312. Dim clr As Integer
  313.     ' Get from_pic's pixels.
  314.     hbm = from_pic.Image
  315.     status = GetObject(hbm, 14, bm)
  316.     from_wid = bm.bmWidthBytes
  317.     from_hgt = bm.bmHeight
  318.     ReDim from_bytes(0 To from_wid - 1, 0 To from_hgt - 1)
  319.     status = GetBitmapBits(hbm, from_wid * from_hgt, from_bytes(0, 0))
  320.     ' Get to_pic's pixels.
  321.     hbm = to_pic.Image
  322.     status = GetObject(hbm, 14, bm)
  323.     to_wid = bm.bmWidthBytes
  324.     to_hgt = bm.bmHeight
  325.     ReDim to_bytes(0 To to_wid - 1, 0 To to_hgt - 1)
  326.     status = GetBitmapBits(hbm, to_wid * to_hgt, to_bytes(0, 0))
  327.         
  328.     ' Set the bounds for to_pic.
  329.     dx = fx2 - fx1
  330.     dy = fy2 - fy1
  331.     r = Sqr(dx * dx + dy * dy)
  332.     tx1 = fx1
  333.     tx2 = fx1 + r
  334.     ty1 = fy1
  335.     ty2 = fy1 + r
  336.     txmid = tx1 + r / 2
  337.     tymid = ty1 + r / 2
  338.     fxmid = (fx1 + fx2) / 2
  339.     fymid = (fy1 + fy2) / 2
  340.     If tx2 >= to_wid Then tx2 = to_wid - 1
  341.     If ty2 >= to_hgt Then ty2 = to_hgt - 1
  342.     ' Perform the transformation.
  343.     For ty = ty1 To ty2
  344.         For tx = tx1 To tx2
  345.             ' See where the point came from.
  346.             dx = tx - txmid
  347.             dy = ty - tymid
  348.             r = Sqr(dx * dx + dy * dy)
  349.             If r = 0 Then
  350.                 fx = 0
  351.                 fy = 0
  352.             Else
  353.                 theta = Arctan2(dx, dy) - r / K - OFFSET
  354.                 fx = r * Cos(theta)
  355.                 fy = r * Sin(theta)
  356.             End If
  357.             fx = fx + fxmid
  358.             fy = fy + fymid
  359.             
  360.             ' Skip it if any of the four nearest
  361.             ' source pixels lie outside the allowed
  362.             ' source area.
  363.             ify = Int(fy)
  364.             ifx = Int(fx)
  365.             If ifx >= fx1 And ifx < fx2 And _
  366.                ify >= fy1 And ify < fy2 Then
  367.                 ' Interpolate using the four nearest
  368.                 ' pixels in from_pic.
  369.                 dy = fy - ify
  370.                 dx = fx - ifx
  371.                 c1 = palentry(from_bytes(ifx, ify)).peRed
  372.                 c2 = palentry(from_bytes(ifx + 1, ify)).peRed
  373.                 c3 = palentry(from_bytes(ifx, ify + 1)).peRed
  374.                 c4 = palentry(from_bytes(ifx + 1, ify + 1)).peRed
  375.                 ' Interpolate in the Y direction.
  376.                 i1 = c1 * (1 - dy) + c3 * dy
  377.                 i2 = c2 * (1 - dy) + c4 * dy
  378.                 ' Interpolate the results in the X direction.
  379.                 clr = i1 * (1 - dx) + i2 * dx
  380.                 to_bytes(tx, ty) = NearestNonstaticGray(clr)
  381.             End If
  382.         Next tx
  383.     Next ty
  384.     ' Update from_pic.
  385.     status = SetBitmapBits(hbm, to_wid * to_hgt, to_bytes(0, 0))
  386.     to_pic.Refresh
  387. End Sub
  388. ' ************************************************
  389. ' Fisheye warping.
  390. ' ************************************************
  391. Sub FisheyePicture( _
  392.     ByVal from_pic As Control, ByVal to_pic As Control, _
  393.     ByVal fx1 As Integer, ByVal fy1 As Integer, _
  394.     ByVal fx2 As Integer, ByVal fy2 As Integer)
  395. Const PI = 3.14159
  396. Dim bm As BITMAP
  397. Dim hbm As Integer
  398. Dim status As Long
  399. Dim from_bytes() As Byte
  400. Dim to_bytes() As Byte
  401. Dim from_wid As Long
  402. Dim from_hgt As Long
  403. Dim to_wid As Long
  404. Dim to_hgt As Long
  405. Dim tx1 As Single
  406. Dim tx2 As Single
  407. Dim ty1 As Single
  408. Dim ty2 As Single
  409. Dim txmid As Single
  410. Dim tymid As Single
  411. Dim fxmid As Single
  412. Dim fymid As Single
  413. Dim fx As Single
  414. Dim fy As Single
  415. Dim tx As Single
  416. Dim ty As Single
  417. Dim x As Single
  418. Dim y As Single
  419. Dim r1 As Single
  420. Dim r2 As Single
  421. Dim ifx As Integer
  422. Dim ify As Integer
  423. Dim dx As Single
  424. Dim dy As Single
  425. Dim c1 As Integer
  426. Dim c2 As Integer
  427. Dim c3 As Integer
  428. Dim c4 As Integer
  429. Dim i1 As Integer
  430. Dim i2 As Integer
  431. Dim clr As Integer
  432. Dim Rmax As Single
  433.     ' Get from_pic's pixels.
  434.     hbm = from_pic.Image
  435.     status = GetObject(hbm, 14, bm)
  436.     from_wid = bm.bmWidthBytes
  437.     from_hgt = bm.bmHeight
  438.     ReDim from_bytes(0 To from_wid - 1, 0 To from_hgt - 1)
  439.     status = GetBitmapBits(hbm, from_wid * from_hgt, from_bytes(0, 0))
  440.     ' Get to_pic's pixels.
  441.     hbm = to_pic.Image
  442.     status = GetObject(hbm, 14, bm)
  443.     to_wid = bm.bmWidthBytes
  444.     to_hgt = bm.bmHeight
  445.     ReDim to_bytes(0 To to_wid - 1, 0 To to_hgt - 1)
  446.     status = GetBitmapBits(hbm, to_wid * to_hgt, to_bytes(0, 0))
  447.         
  448.     ' Set the bounds for to_pic.
  449.     tx1 = fx1
  450.     tx2 = fx2 + 2 * Rmax
  451.     ty1 = fy1
  452.     ty2 = fy2 + 2 * Rmax
  453.     If tx2 >= to_wid Then tx2 = to_wid - 1
  454.     If ty2 >= to_hgt Then ty2 = to_hgt - 1
  455.     txmid = (tx1 + tx2) / 2
  456.     tymid = (ty1 + ty2) / 2
  457.     fxmid = (fx1 + fx2) / 2
  458.     fymid = (fy1 + fy2) / 2
  459.     Rmax = to_wid * 0.75
  460.     ' Perform the transformation.
  461.     For ty = ty1 To ty2
  462.         For tx = tx1 To tx2
  463.             ' See where the point came from.
  464.             dx = tx - txmid
  465.             dy = ty - tymid
  466.             r1 = Sqr(dx * dx + dy * dy)
  467.             If r1 = 0 Then
  468.                 fx = fxmid
  469.                 fy = fymid
  470.             Else
  471.                 r2 = Rmax / 2 * (1 / (1 - r1 / Rmax) - 1)
  472.                 fx = dx * r2 / r1 + fxmid
  473.                 fy = dy * r2 / r1 + fymid
  474.             End If
  475.             ' Skip it if any of the four nearest
  476.             ' source pixels lie outside the allowed
  477.             ' source area.
  478.             ify = Int(fy)
  479.             ifx = Int(fx)
  480.             If ifx >= fx1 And ifx < fx2 And _
  481.                ify >= fy1 And ify < fy2 Then
  482.                 ' Interpolate using the four nearest
  483.                 ' pixels in from_pic.
  484.                 dy = fy - ify
  485.                 dx = fx - ifx
  486.                 c1 = palentry(from_bytes(ifx, ify)).peRed
  487.                 c2 = palentry(from_bytes(ifx + 1, ify)).peRed
  488.                 c3 = palentry(from_bytes(ifx, ify + 1)).peRed
  489.                 c4 = palentry(from_bytes(ifx + 1, ify + 1)).peRed
  490.                 ' Interpolate in the Y direction.
  491.                 i1 = c1 * (1 - dy) + c3 * dy
  492.                 i2 = c2 * (1 - dy) + c4 * dy
  493.                 ' Interpolate the results in the X direction.
  494.                 clr = i1 * (1 - dx) + i2 * dx
  495.                 to_bytes(tx, ty) = NearestNonstaticGray(clr)
  496.             End If
  497.         Next tx
  498.     Next ty
  499.     ' Update from_pic.
  500.     status = SetBitmapBits(hbm, to_wid * to_hgt, to_bytes(0, 0))
  501.     to_pic.Refresh
  502. End Sub
  503. ' ************************************************
  504. ' Warp using:
  505. '   x' = x
  506. '   y' = y + 20(sin(x/100 * PI) + 1)
  507. ' The inverse transformation is:
  508. '   x = x'
  509. '   y = y' - 20(sin(x'/100 * PI) + 1)
  510. ' ************************************************
  511. Sub WavePicture( _
  512.     ByVal from_pic As Control, ByVal to_pic As Control, _
  513.     ByVal fx1 As Integer, ByVal fy1 As Integer, _
  514.     ByVal fx2 As Integer, ByVal fy2 As Integer)
  515. Const PI = 3.14159
  516. Dim bm As BITMAP
  517. Dim hbm As Integer
  518. Dim status As Long
  519. Dim from_bytes() As Byte
  520. Dim to_bytes() As Byte
  521. Dim from_wid As Long
  522. Dim from_hgt As Long
  523. Dim to_wid As Long
  524. Dim to_hgt As Long
  525. Dim tx1 As Single
  526. Dim tx2 As Single
  527. Dim ty1 As Single
  528. Dim ty2 As Single
  529. Dim fx As Single
  530. Dim fy As Single
  531. Dim tx As Single
  532. Dim ty As Single
  533. Dim x As Single
  534. Dim y As Single
  535. Dim ifx As Integer
  536. Dim ify As Integer
  537. Dim dx As Single
  538. Dim dy As Single
  539. Dim c1 As Integer
  540. Dim c2 As Integer
  541. Dim c3 As Integer
  542. Dim c4 As Integer
  543. Dim i1 As Integer
  544. Dim i2 As Integer
  545. Dim clr As Integer
  546.     ' Get from_pic's pixels.
  547.     hbm = from_pic.Image
  548.     status = GetObject(hbm, 14, bm)
  549.     from_wid = bm.bmWidthBytes
  550.     from_hgt = bm.bmHeight
  551.     ReDim from_bytes(0 To from_wid - 1, 0 To from_hgt - 1)
  552.     status = GetBitmapBits(hbm, from_wid * from_hgt, from_bytes(0, 0))
  553.     ' Get to_pic's pixels.
  554.     hbm = to_pic.Image
  555.     status = GetObject(hbm, 14, bm)
  556.     to_wid = bm.bmWidthBytes
  557.     to_hgt = bm.bmHeight
  558.     ReDim to_bytes(0 To to_wid - 1, 0 To to_hgt - 1)
  559.     status = GetBitmapBits(hbm, to_wid * to_hgt, to_bytes(0, 0))
  560.         
  561.     ' Set the bounds for to_pic.
  562.     tx1 = fx1
  563.     tx2 = fx2
  564.     ty1 = fy1
  565.     ty2 = fy2 + 40
  566.     ' Perform the transformation.
  567.     For ty = ty1 To ty2
  568.         For tx = tx1 To tx2
  569.             ' See where the point came from.
  570.             fx = tx
  571.             fy = ty - 20 * (Sin(tx / 100 * PI) + 1)
  572.             ' Skip it if any of the four nearest
  573.             ' source pixels lie outside the allowed
  574.             ' source area.
  575.             ify = Int(fy)
  576.             ifx = Int(fx)
  577.             If ifx >= fx1 And ifx < fx2 And _
  578.                ify >= fy1 And ify < fy2 Then
  579.                 ' Interpolate using the four nearest
  580.                 ' pixels in from_pic.
  581.                 dy = fy - ify
  582.                 dx = fx - ifx
  583.                 c1 = palentry(from_bytes(ifx, ify)).peRed
  584.                 c2 = palentry(from_bytes(ifx + 1, ify)).peRed
  585.                 c3 = palentry(from_bytes(ifx, ify + 1)).peRed
  586.                 c4 = palentry(from_bytes(ifx + 1, ify + 1)).peRed
  587.                 ' Interpolate in the Y direction.
  588.                 i1 = c1 * (1 - dy) + c3 * dy
  589.                 i2 = c2 * (1 - dy) + c4 * dy
  590.                 ' Interpolate the results in the X direction.
  591.                 clr = i1 * (1 - dx) + i2 * dx
  592.                 to_bytes(tx, ty) = NearestNonstaticGray(clr)
  593.             End If
  594.         Next tx
  595.     Next ty
  596.     ' Update from_pic.
  597.     status = SetBitmapBits(hbm, to_wid * to_hgt, to_bytes(0, 0))
  598.     to_pic.Refresh
  599. End Sub
  600. ' ***********************************************
  601. ' Load the control's palette so the non-static
  602. ' colors are grays. Map the logical palette to
  603. ' match the system palette. Convert the image to
  604. ' use the non-static grays.
  605. ' Set the following module global variables.
  606. '   LogPal      Image logical palette handle.
  607. '   palentry()  Image logical palette entries.
  608. '   wid         Width of image.
  609. '   hgt         Height of image.
  610. '   bytes(1 To wid, 1 To hgt)
  611. '               Image pixel values.
  612. ' ***********************************************
  613. Sub MatchGrayPalette(pic As Control)
  614. Dim sys(0 To 255) As PALETTEENTRY
  615. Dim i As Integer
  616. Dim bm As BITMAP
  617. Dim hbm As Integer
  618. Dim status As Long
  619. Dim x As Integer
  620. Dim y As Integer
  621. Dim gray As Single
  622. Dim dgray As Single
  623. Dim c As Integer
  624. Dim clr As Integer
  625.     ' Make sure pic has the foreground palette.
  626.     pic.ZOrder
  627.     i = RealizePalette(pic.hdc)
  628.     DoEvents
  629.     ' Get the system palette entries.
  630.     i = GetSystemPaletteEntries(pic.hdc, 0, SysPalSize, sys(0))
  631.         
  632.     ' Get the image pixels.
  633.     hbm = pic.Image
  634.     status = GetObject(hbm, 14, bm)
  635.     wid = bm.bmWidthBytes
  636.     hgt = bm.bmHeight
  637.     ReDim bytes(1 To wid, 1 To hgt)
  638.     status = GetBitmapBits(hbm, wid * hgt, bytes(1, 1))
  639.     ' Make the logical palette as big as possible.
  640.     LogPal = pic.Picture.hPal
  641.     If ResizePalette(LogPal, SysPalSize) = 0 Then
  642.         Beep
  643.         MsgBox "Error resizing logical palette.", _
  644.             vbExclamation
  645.         Exit Sub
  646.     End If
  647.     ' Blank the non-static colors.
  648.     For i = 0 To StaticColor1
  649.         palentry(i) = sys(i)
  650.     Next i
  651.     For i = StaticColor1 + 1 To StaticColor2 - 1
  652.         With palentry(i)
  653.             .peRed = 0
  654.             .peGreen = 0
  655.             .peBlue = 0
  656.             .peFlags = PC_NOCOLLAPSE
  657.         End With
  658.     Next i
  659.     For i = StaticColor2 To 255
  660.         palentry(i) = sys(i)
  661.     Next i
  662.     i = SetPaletteEntries(LogPal, 0, SysPalSize, palentry(0))
  663.     ' Insert the non-static grays.
  664.     gray = 0
  665.     dgray = 255 / (StaticColor2 - StaticColor1 - 2)
  666.     For i = StaticColor1 + 1 To StaticColor2 - 1
  667.         c = gray
  668.         gray = gray + dgray
  669.         With palentry(i)
  670.             .peRed = c
  671.             .peGreen = c
  672.             .peBlue = c
  673.         End With
  674.     Next i
  675.     i = SetPaletteEntries(LogPal, StaticColor1 + 1, StaticColor2 - StaticColor1 - 1, palentry(StaticColor1 + 1))
  676.     ' Recreate the image using the new colors.
  677.     For y = 1 To hgt
  678.         For x = 1 To wid
  679.             clr = bytes(x, y)
  680.             With sys(clr)
  681.                 c = (CInt(.peRed) + .peGreen + .peBlue) / 3
  682.             End With
  683.             bytes(x, y) = NearestNonstaticGray(c)
  684.         Next x
  685.     Next y
  686.     status = SetBitmapBits(hbm, wid * hgt, bytes(1, 1))
  687.     ' Realize the gray palette.
  688.     i = RealizePalette(pic.hdc)
  689.     pic.Refresh
  690. End Sub
  691. ' ************************************************
  692. ' Return the index of the nonstatic gray closest
  693. ' to the given value (assuming the non-static
  694. ' colors are a gray scale created by
  695. ' MatchGrayPalette).
  696. ' ************************************************
  697. Function NearestNonstaticGray(c As Integer) As Integer
  698. Dim dgray As Single
  699.     If c < 0 Then
  700.         c = 0
  701.     ElseIf c > 255 Then
  702.         c = 255
  703.     End If
  704.     dgray = 255 / (StaticColor2 - StaticColor1 - 2)
  705.     NearestNonstaticGray = c / dgray + StaticColor1 + 1
  706. End Function
  707. ' ************************************************
  708. ' Create the warped image.
  709. ' ************************************************
  710. Private Sub CmdWarp_Click()
  711.     WaitStart
  712.     DrawImage
  713.     WaitEnd
  714. End Sub
  715. Private Sub Form_Load()
  716. Dim i As Integer
  717.     ' Make sure the screen supports palettes.
  718.     If Not GetDeviceCaps(hdc, RASTERCAPS) And RC_PALETTE Then
  719.         Beep
  720.         MsgBox "This monitor does not support palettes.", _
  721.             vbCritical
  722.         End
  723.     End If
  724.     ' Get system palette size and # static colors.
  725.     SysPalSize = GetDeviceCaps(hdc, SIZEPALETTE)
  726.     NumStaticColors = GetDeviceCaps(hdc, NUMRESERVED)
  727.     StaticColor1 = NumStaticColors \ 2 - 1
  728.     StaticColor2 = SysPalSize - NumStaticColors \ 2
  729.     ' Make a deafult selection.
  730.     WarpCombo.ListIndex = 0
  731.     ' Make the pictures all use gray palettes.
  732.     Me.Show
  733.     DoEvents
  734.     WaitStart
  735.     MatchGrayPalette ToPict
  736.     DoEvents
  737.     ' Let each image repair its palette if needed.
  738.     FromPict.ZOrder
  739.     DoEvents
  740.     ToPict.ZOrder
  741.     DoEvents
  742.     WaitEnd
  743. End Sub
  744. ' ***********************************************
  745. ' Reset the cursors for the form and all the
  746. ' picture boxes.
  747. ' ***********************************************
  748. Sub WaitEnd()
  749.     MousePointer = vbDefault
  750.     FromPict.MousePointer = vbDefault
  751.     ToPict.MousePointer = vbDefault
  752. End Sub
  753. ' ***********************************************
  754. ' Give the form and all the picture boxes an
  755. ' hourglass cursor.
  756. ' ***********************************************
  757. Sub WaitStart()
  758.     MousePointer = vbHourglass
  759.     FromPict.MousePointer = vbHourglass
  760.     ToPict.MousePointer = vbHourglass
  761.     DoEvents
  762. End Sub
  763. Private Sub Form_Unload(Cancel As Integer)
  764.     End
  765. End Sub
  766. Private Sub mnuFileExit_Click()
  767.     Unload Me
  768. End Sub
  769. ' ***********************************************
  770. ' Load a new image file.
  771. ' ***********************************************
  772. Private Sub mnuFileLoad_Click()
  773. Dim fname As String
  774.     ' Allow the user to pick a file.
  775.     On Error Resume Next
  776.     FileDialog.filename = "*.BMP;*.ICO;*.RLE;*.WMF;*.DIB"
  777.     FileDialog.Flags = cdlOFNFileMustExist + cdlOFNHideReadOnly
  778.     FileDialog.ShowOpen
  779.     If Err.Number = cdlCancel Then
  780.         Exit Sub
  781.     ElseIf Err.Number <> 0 Then
  782.         Beep
  783.         MsgBox "Error selecting file.", , vbExclamation
  784.         Exit Sub
  785.     End If
  786.     On Error GoTo 0
  787.     fname = Trim$(FileDialog.filename)
  788.     FileDialog.InitDir = Left$(fname, Len(fname) _
  789.         - Len(FileDialog.FileTitle) - 1)
  790.     ' Load the picture.
  791.     WaitStart
  792.     LoadFromPict fname
  793.     WaitEnd
  794. End Sub
  795. ' ***********************************************
  796. ' Load the indicated file and prepare to work
  797. ' with its palette.
  798. ' ***********************************************
  799. Sub LoadFromPict(fname As String)
  800. Dim status As Long
  801.     On Error GoTo LoadFileError
  802.     FromPict.Picture = LoadPicture(fname)
  803.     On Error GoTo 0
  804.         
  805.     MatchGrayPalette FromPict
  806.     ToPict.Cls
  807.     Caption = "Warp [" & fname & "]"
  808.     CmdWarp.Enabled = True
  809.     Exit Sub
  810. LoadFileError:
  811.     Beep
  812.     MsgBox "Error loading file " & fname & "." & _
  813.         vbCrLf & Error$
  814.     Exit Sub
  815. End Sub
  816.