threaded image downloader.bmx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. ' -----------------------------------------------------------------------------
  2. ' MAKE SURE "Threaded Build" IS CHECKED IN THE Program -> Build Options menu!
  3. ' -----------------------------------------------------------------------------
  4. ' You may have to tell your firewall to let this program through...
  5. ' -----------------------------------------------------------------------------
  6. ' Global mutex and abort 'signal' checked in thread...
  7. ' -----------------------------------------------------------------------------
  8. Global abortmutex:TMutex = CreateMutex ()
  9. Global abort = 0
  10. ' -----------------------------------------------------------------------------
  11. Global Bail = 3 ' How many times to attempt download of each image...
  12. ' -----------------------------------------------------------------------------
  13. ' Number of image URLs in array below...
  14. Const PicNum = 7
  15. Global Pic$ [PicNum]
  16. Pic [0] = ConvURL ("http://www.blitzbasic.com/img/platypus.jpg")
  17. Pic [1] = ConvURL ("http://www.blitzbasic.com/img/auto_cross_racing.jpg")
  18. Pic [2] = ConvURL ("http://www.blitzbasic.com/img/super_gerball.jpg")
  19. Pic [3] = ConvURL ("http://www.blitzbasic.com/img/tank_universal.jpg")
  20. Pic [4] = ConvURL ("http://www.blitzbasic.com/img/tecno.jpg")
  21. Pic [5] = ConvURL ("http://www.blitzbasic.com/img/master_of_defence.jpg")
  22. Pic [6] = ConvURL ("http://www.blitzbasic.com/img/kingdom_elemental_tactics.jpg")
  23. ' -----------------------------------------------------------------------------
  24. ' D E M O . . .
  25. ' -----------------------------------------------------------------------------
  26. AppTitle = "Threaded image downloader..."
  27. Graphics 640, 480
  28. SetClsColor 64, 96, 128
  29. AutoMidHandle True
  30. ' -----------------------------------------------------------------------------
  31. ' Player type stores downloaded images and their co-ords...
  32. ' -----------------------------------------------------------------------------
  33. Type Player
  34. Field x:Float = Rnd (GraphicsWidth ())
  35. Field y:Float = Rnd (GraphicsHeight ())
  36. Field xs:Float = Rnd (10)
  37. Field ys:Float = Rnd (10)
  38. Field ang:Float = Rnd (360)
  39. Field angspeed:Float = Rnd (-5, 5)
  40. Field scale:Float = Rnd (1.0, 3.0)
  41. Field image:TImage
  42. End Type
  43. ' -----------------------------------------------------------------------------
  44. ' List of Player objects...
  45. ' -----------------------------------------------------------------------------
  46. PlayerList:TList = CreateList ()
  47. ' -----------------------------------------------------------------------------
  48. ' Spawn first thread...
  49. ' -----------------------------------------------------------------------------
  50. index = 0 ' Picture index in Pic [] array...
  51. Print ""; Print "Downloading " + Pic [index]
  52. pixthread:TThread = CreateThread (DownloadPixmap, Pic [index])
  53. alldone = 0
  54. Repeat
  55. ' This variable is set when all images have been downloaded:
  56. If Not alldone
  57. If Not ThreadRunning (pixthread)
  58. ' WaitThread contains the result of the last thread (now finished)...
  59. pix:TPixmap = TPixmap (WaitThread (pixthread))
  60. ' If a valid pixmap was returned, create a new 'Player' object
  61. ' and load the pixmap as an image...
  62. If pix
  63. p:Player = New Player
  64. p.image = LoadImage (pix)
  65. ListAddLast PlayerList, p
  66. EndIf
  67. ' Check we still have more images to load...
  68. If index < PicNum - 1
  69. ' OK... next!
  70. index = index + 1
  71. Print ""; Print "Downloading " + Pic [index]
  72. ' Last image thread is done/processed, so create a new one!
  73. pixthread = CreateThread (DownloadPixmap, Pic [index])
  74. Else
  75. Print ""; Print "All images loaded!"
  76. alldone = 1 ' All images in array loaded!
  77. EndIf
  78. EndIf
  79. EndIf
  80. Cls
  81. ' Draw all loaded images...
  82. For p:Player = EachIn PlayerList
  83. p.x = p.x + p.xs
  84. If p.x < 0 Or p.x > GraphicsWidth () - 1
  85. p.xs = -p.xs
  86. EndIf
  87. p.y = p.y + p.ys
  88. If p.y < 0 Or p.y > GraphicsHeight () - 1
  89. p.ys = -p.ys
  90. EndIf
  91. SetScale p.scale, p.scale
  92. p.ang = p.ang + p.angspeed
  93. SetRotation p.ang
  94. DrawImage p.image, p.x, p.y
  95. SetScale 1, 1
  96. SetRotation 0
  97. If alldone
  98. txt$ = "All images loaded!"
  99. Else
  100. txt$ = "Loading images in background..."
  101. EndIf
  102. SetColor 0, 0, 0
  103. DrawText txt$, 20, 20
  104. SetColor 255, 255, 255
  105. DrawText txt$, 18, 18
  106. Next
  107. Flip
  108. Until KeyHit (KEY_ESCAPE)
  109. ' Lock the abort mutex so we can safely modify the global abort variable, which
  110. ' is then checked by the thread to allow a safe exit...
  111. LockMutex abortmutex
  112. abort = True
  113. UnlockMutex abortmutex
  114. ' The mutex is unlocked by the DownloadPixmap thread before returning,
  115. ' but it may already have exited. I think, hence the UnlockMutex above,
  116. ' just in case...
  117. ' Now wait to make sure the thread has finished...
  118. WaitThread pixthread
  119. ' Done!
  120. End
  121. ' -----------------------------------------------------------------------------
  122. ' Threaded pixmap downloader...
  123. ' -----------------------------------------------------------------------------
  124. Function DownloadPixmap:TPixmap (data:Object)
  125. img$ = String (data)
  126. Local pix:TPixmap ' Downloaded pixmap...
  127. Local url:TStream ' Download stream...
  128. Local copy:TStream ' Local copy of download...
  129. Local count:Int ' Byte count during download...
  130. Local retry:Int ' If download fails, retry 'Bail' times...
  131. Local quit:Int ' Too many fails, exit...
  132. Repeat
  133. Print ""
  134. Print "Attempting new download..."
  135. Print ""
  136. url = ReadStream (img$)
  137. If url
  138. ' Create local copy...
  139. copy = WriteStream ("local.jpg")
  140. If copy
  141. ' Reset byte count...
  142. count = 0
  143. Repeat
  144. ' Try to lock mutex, to check global abort variable, which
  145. ' is set to True before exiting program...
  146. LockMutex abortmutex
  147. If abort
  148. ' Aaaaaaahhhh!!! We're going down!!!
  149. UnlockMutex abortmutex
  150. ' Close all streams! Batten down the hatches!
  151. CloseStream url
  152. CloseStream copy
  153. ' Abandon ship!
  154. Return Null
  155. Else
  156. ' Not aborting, so unlock the mutex...
  157. UnlockMutex abortmutex
  158. ' Not every efficient (one byte at a time), but works as a demo...
  159. WriteByte copy, ReadByte (url)
  160. ' Count bytes downloaded...
  161. count = count + 1
  162. If count Mod 1024 = 0 Then Print count + " bytes downloaded in background"
  163. EndIf
  164. Until Eof (url)
  165. CloseStream copy
  166. ' Try to load pixmap...
  167. pix = LoadPixmap ("local.jpg")
  168. EndIf
  169. CloseStream url
  170. EndIf
  171. ' Download failed? Retry 'Bail' times...
  172. If pix = Null
  173. retry = retry + 1
  174. If retry = Bail
  175. quit = True
  176. Print "Failed to download after " + Bail + " attempts..."
  177. Else
  178. Print "Retrying..."
  179. EndIf
  180. EndIf
  181. Until pix Or quit
  182. If pix = Null
  183. DebugLog "Oops... problem loading " + img$
  184. EndIf
  185. Return pix ' May still be Null after 'Bail' failed attempts...
  186. End Function
  187. ' Convert real URL to BlitzMax stream-friendly URL...
  188. Function ConvURL$ (url$)
  189. Return Replace (url$, "://", "::")
  190. End Function