Loading Local Images into the Slider

There are several different ways you can import images into a movie running in a Projector (or in Authoring). The first step for all the techniques is getting a list of files to import.

For example, if the images are in a folder called "Images" which is in the same folder as the movie, then a function like this will return a list of the JPGs in that folder:

on GetListOfImages (me, inDirectory)
  -- returns a list of files (full path) in specified directory
  fileList = [ ] 
  the itemDelimiter = "." 
  repeat with i = 1 to the maxInteger 
    n = getNthFileNameInFolder(inDirectory , i) 
    if n = EMPTY then exit repeat 
    if n.item[n.item.count] = "jpg" then 
      fileList.append(inDirectory & n) 
    end if 
  end repeat 
  return fileList
end

Once you have this list, you can loop through at 'import' the images. One technique for doing this is to set the fileName of a placeholder cast member. For example

member("PlaceHolder").filename = fileList[1]

Since our slider may use many images, and we only want to create a small thumbnail image for each, it is inefficient to load all the images into memory at once. For this reason, the following script will first load a 'place holder' graphic (which says "image loading") for each file into the slider. Then, one-by-one, it loads the real image into the slider (replacing the place holder as the real image is loaded).

Example source file available here

ImageLoader.local (Parent script)

-- loads images from a local directory (not for shockwave)
property myTempBitmap, mySlider, myIndx, myImagesToLoad
property myTarget


on new (me)
  
  myTempBitmap = member("ImageLoader.local.bitmap")
  if myTempBitmap.type <> #bitmap then 
    myTempBitmap = new(#bitmap)
    myTempBitmap.name = "ImageLoader.local.bitmap"
  end if
  return me
end

on Destroy (me)
  -- erase the bitmap
  if myTempBitmap.ilk = #member then erase myTempBitmap
  -- void our reference to the slider
  myTarget = VOID
end

on stopMovie (me)
  -- will get this message if the timeout is active
  me.Destroy()
end

on loadImagesTo (me, theTargetObject, FolderOfImages)
  -- get list of files to load
  imageFiles = me._GetFileNames(FolderOfImages)
  myTarget = theTargetObject
  -- now load a temporary image into the slider for each real image
  myImagesToLoad = [:]
  repeat with aFilePath in imageFiles
    myImagesToLoad.addProp(aFilePath, member("SliderLoadingImage").image)
  end repeat
  myTarget.LoadImages(myImagesToLoad)
  
  -- now create a thread to actually load the real images
  myIndx = 0
  thread = timeout("ImageLoaderThread").new(100, #LoadNextImage, me)
  
end

on LoadNextImage (me, aTimeout)
  -- called by the timeout
  if myIndx <  myImagesToLoad.count then 
    myIndx = myIndx + 1
    whichFile = myImagesToLoad.getPropAt(myIndx)
    myTempBitmap.filename = whichFile
    -- replace the 'loading' image with the real one
    myTarget.SetImageAt(myTempBitmap.image, whichFile, myIndx)
  else
    aTimeout.forget()
  end if
end

on _GetFileNames (me, inDirectory)
  -- returns a list of files (full path) in specified directory
  fileList = [ ] 
  the itemDelimiter = "." 
  repeat with i = 1 to the maxInteger 
    n = getNthFileNameInFolder(inDirectory , i) 
    if n = EMPTY then exit repeat 
    if n.item[n.item.count] = "jpg" then 
      fileList.append(inDirectory & n) 
    end if 
  end repeat 
  return fileList
end

To demonstrate how this script works with the Slider, here is a behaviour that creates the slider and an instance of this Loader script:

property ancestor
property myMidH, myShift, myAlpha, myOffset
property myTrackingFlag, myStartH
property mySlideLeftRect, mySlideRightRect

on beginSprite me
  
  thisSprite = sprite(me.spriteNum)
  thisRect = thisSprite.rect
  thisMember = thisSprite.member
  thisCanvas = thisMember.image
  thisCanvas.fill(thisCanvas.rect, rgb("#000000"))
  
  --
  myOffset = point(thisRect.left, thisRect.top)
  myMidH = thisSprite.left + (thisSprite.width/2)
  
  -- create the 'hot spots' for sliding
  mySlideLeftRect = rect(thisSprite.left, thisSprite.top, thisSprite.left \
+ (thisSprite.width/3), thisSprite.bottom)
  mySlideRightRect = rect(thisSprite.right-(thisSprite.width/3), \
thisSprite.top, thisSprite.right, thisSprite.bottom)
  
  -- create the slider object
  ancestor = script("HorizontalImageSlider.Class").new()
  me.Initialise(thisCanvas, thisCanvas.rect)
  
  
  -- set the path to the folder containing theimages
  sep = the last char of the moviePath
  folderContainingImages = the moviePath & "Images" & sep
  
  -- create an Object to load up the images
  imageLoaderDaemon = script("ImageLoader.local").new()
  imageLoaderDaemon.loadImagesTo(me,folderContainingImages)
  
  
end

on endSprite (me)
  -- clean up the canvas 
  thisSprite = sprite(me.spriteNum)
  thisMember = thisSprite.member
  thisCanvas = thisMember.image
  thisCanvas.fill(thisCanvas.rect, rgb("#000000"))
end	


on enterframe (me)
  if myTrackingFlag then
    -- the mouse was clicked on this sprite
    if not (the mouseDown) then 
      -- stop tracking
      myTrackingFlag = 0
    else
      -- 'drag' the slider to the current mouse location
      mH = the mouseH
      amt = myStartH - mH
      myStartH = mH
      me.Slide(amt)
    end if
  else
    p = the mouseLoc
    if inside(p, mySlideLeftRect) then
      proposedAmt =  myShift -1
      myShift = Max(-10, proposedAmt)
      
    else  if inside(p, mySlideRightRect) then
      proposedAmt =  myShift + 1
      myShift = Min(10, proposedAmt)
      
    else
      -- slow down to a stop
      myShift = myShift * 0.75
      if abs(myShift) < 2 then myShift = 0
    end if
    me.Slide(myShift)
  end if
end

on mouseDown (me)
  ClickedTile = me.GetTileIDAtPoint(the mouseLoc - myOffset)
  if voidP(ClickedTile) then return 0
  myTrackingFlag = 1
  myShift= 0
  myStartH = the mouseH
  me.SelectTileByID(ClickedTile, (the shiftDown))
  sendAllSprites(#ImageSelected, ClickedTile)
end
Last updated 20th June, 2005

joao said

Thanks for the script and the site. Keep up the good working.

Posted 4th March, 2006

Michael said

Yes I agree ... extremely smooth script. I would like to know how to modify to scroll vertically. The end result probably wouldn?t be that intuitive for the user but I would like to see it never the less. I have redesigned the slider sprite to run vertically however I have searched and searched and searched and I cannot work out where the script stipulates that the image must be placed left to right (I?m wanting to have them load underneath each other) nor where I can manipulate the script to have the slider scroll up and down.

Cheers, michael

Posted 1st August, 2006

Luke said

Hi,

Have a look in the "Slide" method, about two thirds of the way down, for these lines:

rectLeft = -myMapH
...
destRect = myMap[aTileIdx][#DRect].offset(rectLeft, 0)

This is stipulating that the 'destination rect' for each is to the left of the last rect. So you will want to change it to something like

rectBottom=-myMapV
...
destRect = myMap[aTileIdx][#DRect].offset(0, rectBottom)

to paint each tile below the one above. Changing the value of rectBottom will make the slider go up and down. (Note - the variable myMapV doesn't exist in the code. you will need to change myMapH to myMapV). If you are still stuck, let me know (I have a vertical version somewhere I can upload)

-- Luke

Posted 2nd August, 2006

Michael said

I'm with you now :) ... I got a little lost in the "...myMap[aTileIdx][#DRect]..." strings and it never really 'clicked' to research the offset function. I'm currently having a play around - ironed out most the bugs just one more tracking one to go. Thanks for your wisdom Luke.

- michael

Posted 2nd August, 2006

Gianluca said

Can you help me?

I run your source download file and all works fine (no code error),
but if i try to copy the castmembers and the sprite in another movie i recive this error:

script error:

Object expected.
Thread = timeout ("imageloader Thread").new(100, #loadnextimage, me)

i've assigned the HorizontalImageSlider.Behaviour to the bitmap sprite, i've to do something else?

Thanks for your help...

Posted 11th October, 2006

Luke said

Hi

That line uses the old syntax for creating timeout objects (it works fine when you open the flle with DMX2004 because director will run the movie in 'compatibility mode' and set the 'scriptExecutionStyle= 9'). When you paste the code into a new movie, the old syntax will error unless you explicitly set the scriptExecutionStyle. Better yet, change the code so it used the new DMX2004 syntax like this:

OLD SYNTAX:
Thread = timeout ("imageloader Thread").new(100, #loadnextimage, me)

NEW SYNTAX
Thread = timeout ().new("imageloader Thread", 100, #loadnextimage, me)

-- Luke

Posted 11th October, 2006

Dave said

Hi

Great script, ideal for presenting artwork or photos in director.

The horizontal scroll looks great but would it be possible to upload the vertical scroll version. You mentioned that you already have a vertical version .

I've made the changes Michael requested but it still isn't working properly.

Thanks

Dave

Posted 13th February, 2007

Alex Souza said

Great job! Quick question: is there a way to stop the slider when it finds the last image (currently there is a continuous loop)?my idea is to open with the first image allowing the user to move rigth to the last image (and vice-versa).
thanks a lot,
Alex

Posted 9th December, 2007

lucio said

Ã? una bellissima funzione e va bene nel proiector, ma non funziona se viene pubblicata in .dcr o in html
Messaggio di errore: Use of unsupported Lingo command
#getNthFileNameInFolder !!! Funziona solo nel Proiector?

Posted 12th July, 2009

Add Your Comment






[Preview]


Verification image

Note - paragraph formatting and links (h-refs) are handled automatically. Most HTML is removed (though some like <em><strong> are allowed). Email addresses are never displayed.

Pithy and yet enlightening comments most welcome. Spammy or unreasonably obnoxious comments zapped without apology


© 2006 MeccaMedialight. Site Powered by Wrangler 8.