Creating a file downloader in Creo

It does not compute
6 min readNov 3, 2018

--

I wanted to download imagery and other files so that I can serve them offline, but Creo does not offer that as an out of the box capability, so I had to do some tinkering in order to make it work.

The concept displayed below works on images only, but it could easily be expanded to other file types.

We start off by creating two HTTPClients, and one HTTP Request in each one of them:

The first HTTPRequest (HTTPClient1) gets the list of files that need to be downloaded. Think of it like going to your app’s server and finding out what needs to be downloaded.

In the demo I made, I got a list of 5 files from https://sample-videos.com, which has images of different file sizes, and these are great for any sort of testing purposes. They have multiple file types for testing as well, such as videos, PDF’s, Zip files and more.

So I made a short json file that contains the url’s of those files and posted it online here: https://dont-be-a-tourist.firebaseio.com/files.json

Now I just point HTTPClient1 to https://dont-be-a-tourist.firebaseio.com and Request1 to /files.json. Don’t forget the method to be Get instead of the default Post.

Ok, next step is to store those values globally, so we create a download cue.

Click on the Window1 object, and create a file array object, let’s call it fArr.

If you don’t know how, click on Window1, and click the Code inspector button, top right:

Now, under properties, click the + button to create a new property and name it fArr (automatically renamed to _fArr), but don’t worry about that.

Just right click the property, and select Convert to computed property.

And now you have your property converted, with a proper name.

Ok, if you click Play now, nothing will happen. That’s because even though we have a HTTPClient, we’re not really executing it.

Let’s fix that.

Click Window1 > Events > DidShow and type in the following code:

HTTPClient1.Request1.run();
fArr = [];

What we’re doing with this code, is we’re telling Creo, when Window1 shows up, execute HTTPClient1 (download the file list) and initiate fArr as an array so we can store the values of the files we want to download.

Ok, now the file list will be received via HTTPClient1, but nothing happens after that. Let’s change that.

Open HTTPClient1 > Request1, and select Events > DidFinish

What we’ll do is get the values for the files we want to download them, and store them in fArr like this:

var json = self.value;
for (var f in json){
var url = f.url;
fArr.push(url);
}

self.value is the value we get back from HTTPRequest1, which is the json output.

Next we start a loop for the values in the json. We want just the URL, not the entire JSON.

This is what I mean by that. The output is an array of objects:

[{"url":"https://sample-videos.com/img/Sample-jpg-image-1mb.jpg"},{"url":"https://sample-videos.com/img/Sample-jpg-image-2mb.jpg"},{"url":"https://sample-videos.com/img/Sample-jpg-image-5mb.jpg"},{"url":"https://sample-videos.com/img/Sample-jpg-image-10mb.jpg"},{"url":"https://sample-videos.com/img/Sample-jpg-image-500kb.jpg"}]

When we do var f in json, we get each value separately, which is an object:

{"url":"https://sample-videos.com/img/Sample-jpg-image-1mb.jpg"}

If we want to download the file, we just need the url, not the object, so we declare var url = f.url, which effectively gives us just the url:

https://sample-videos.com/img/Sample-jpg-image-1mb.jpg

Ok, cool, we have the URL of the file, now let’s place it in the queue:

fArr.push(url);

Great. Once the for loop completes, we have a queue of files.

Now we need to initiate the download.

For that we need a couple of things:

  1. The files need to be on the same server, as HTTPClient2 needs to be set to a certain URL (although this may not be true, as you can manipulate the HTTPClient url property, but I’ve not tested that).
  2. Set the HTTPClient2.Request1 path property and run the request.

Ok, so go ahead and add a HTTPClient2 with the URL of your domain where you store the files (in this example case, that’s https://sample-videos.com/).

Then add an empty Request1 with no path, Get as method and Image as the Serializer:

Ok, if you test this it wont work, as we’ll populate it dynamically.

The idea is that this object will get a value from the fArr queue, download it, remove the file from the queue and do that again until there are no more files.

Oh, and we’ll also need one FileManager object and one ImageView, so just drag them on to Window1.

As mentioned earlier, HTTPClient2.Request1 does not have a path, so we have to go back to our first request (HTTPClient1.Request1) to populate that and initiate the first download.

So click HTTPClient1.Request1 > DidFinish, and add more code in there:

var lastEl = fArr.count;
var l = fArr[lastEl-1]
Console.write(l)
var fPath = l.replace('https://sample-videos.com/','');
Console.write(fPath)
HTTPClient2.Request1.path = fPath;
HTTPClient2.Request1.run()

We get the last element in our queue, replace the url so we’re only left with the path, we tell HtTPClient2.Request1 what the path is, and we run HTTPClient2.Request1 using the .run() method.

This is what the final code for HTTPClient1.Request1 DidFinish event looks like:

Our first download has began! Now we have to save it, remove it from the queue and start the next download.

Open HTTPClient2.Request1 DidFinish event.

To save the file, we need a filename. We can get that through the self.path method and doing some string manipulation.

Console.write(self.path)
var p = self.path;
var fnarr = p.split('/');
var fnarrlen = fnarr.count - 1;
var fname = fnarr[fnarrlen];
Console.write('fname = \(fname)');

To get the file data it self, we use the self.value method. But to save it we need to represent it as an image:

var image = self.value;
var data = image.JPEGRepresentation(0.8);

After that, we’ll save it:

var documentsPath = FileManager.directory(SearchPath.Documents);
var filePath = FileManager.appendPath(documentsPath,fname)
var f = FileManager1.createFile(filePath, data);

To see the file we downloaded, we can assign the value to the ImageView we dropped on our canvas:

ImageView1.image = self.value;

Ok, we downloaded the file, we saved it and displayed it in the ImageView.

Now we need to get the next file in the queue, and do this all over again:

if (fArr.count!=0 ){
var photo = fArr.pop();
self.path = photo;
self.run();
} else {
Console.write('No files in queue')
}

We check if there are any more files in the queue using the count method. If there are more files, we get the next file using the pop method (which also removes the file from the queue). We tell the request that the path is the photo property, and we run the request.

Magic! It now works for all files!

Here’s the final code for HTTPClient2.Request1 DidFinish event:

Console.write('Download finished');
Console.write(self.path)
var p = self.path;
var fnarr = p.split('/');
var fnarrlen = fnarr.count - 1;
var fname = fnarr[fnarrlen];
Console.write('fname = \(fname)');
var image = self.value;
var data = image.JPEGRepresentation(0.8);
var documentsPath = FileManager.directory(SearchPath.Documents);
var filePath = FileManager.appendPath(documentsPath,fname)
var f = FileManager1.createFile(filePath, data);
ImageView1.image = self.value;
if (fArr.count!=0 ){
var photo = fArr.pop();
self.path = photo;
self.run();
} else {
Console.write('No files in queue')
}

And this is what that looks like when we run it:

Here’s the Creo file too:

https://www.dropbox.com/s/3ub3skkh48yu3ro/demo-file-downloader.creoproject.zip?dl=0

--

--

It does not compute

I was assempled by my master at 0500 sometimes in the 70's. I am working under optimum parameters.