Monday, December 19, 2011

HTML5 FileAPI: Display Drag n Drop image file

Sometimes accidents are great, and as always, something can be learned. Yesterday, while trying to figure out a way to display .csv files in the web browser, I stumbled upon FileAPI, some sort of HTML5 library...or something (can't display .csv files though...I was just distracted :D). One of the uses that has become apparent to me and others is that files can be dropped straight into the web browser, and then you can read the information that it contains.

Quick video here.
FileReader Docs (by Mozilla) here, this is mainly what I will be describing.
Other links here, here and here.

So, for the rest of this post, I'm just going to paste some code so you can do what snowcrashbeta did (Video link above). All you will need is an index.html file and an associated script.js file. You don't really need to know much JS, but it helps find problems. The way I would describe whats going on is that:
  • elements on the website wait for specific actions to occur,
  • when they do (a file is dropped onto it), a js function is called which then (and depending on how you set it up) takes the file and reads the information embedded in it (filename, type, size etc.), 
  • once it is read, you can then display this information or do something else...like display the image. Somewhere along the line, the file is also uploaded, how neat is that!
Below will be the code, and MY interpretation of what's going on. Yes, there is a high chance that I could be wrong, but I did do a little bit of reading...

index.html
<head>
 <title>Drag n Drog</title>
 <meta http-equiv="content-type" content="text/html;charset=utf-8" />
 <meta name="generator" content="Geany 0.20" />
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<style>
 div { border-radius: 20px; margin-bottom: 10px; padding: 15px; }
 #wrapper { margin: 20px auto; max-width: 600px; }
 #dropper { border: 5px dashed #ccc; height: 100px; text-align: center; font-size: 60px; color: #ccc;}
 #fileinfo { border: 5px solid black; height: 30px; }
 #filedata { border: 5px solid black; height: 250px; }
</style>
</head>

<body>
<div id="wrapper">
 <div id="dropper">Drop File Here</div>
 <div id="fileinfo">File Info</div>
 <div id="filedata"><img id="fileimage" src="" alt="Image"/></div>
</div>
 
 <script src="script.js"></script>
 
</body>
</html>

<head></head>: where the title, links to script files and styles are stated
  • <script src="https://ajax.googleapis... the location of the FileAPI (I think?)
  • div#wrapper...#dropper...#fileinfo...#filedata... CSS styles for these tags
<body> </body>: what people will see
  • <div id="dropper">... dropper element. Where users will drop files.
  • <div id="fileinfo">... fileinfo element. Where information about the file is displayed.
  • <div id="filedata">... filedata element. Holds the image since <img> tags do not have a border option (I'm sure there's a work around).
    • <img id="fileimage" src=""... within the <div id="filedata"... tags. This is where the image will be loaded after the user drops it
  •  <script src="script.js">...load our script file. Note: this can be put up the top of file where the other one was, with the effect that this file will be loaded before the rest of the page will be loaded. Also, the <script... up the top can be put here, but will be loaded after everything else.
The website should look like this. And if you drop an image onto the element, it should display in the box below. So what's going on? Read on.

script.js
$(document).ready(function() {
 var dropbox = document.getElementById("dropper");
 
 dropbox.addEventListener("dragover", dragOver, false);
 dropbox.addEventListener("drop", drop, false);
});

function dragOver(evt) {
 evt.stopPropagation();
 evt.preventDefault();
}

function drop(evt) {
 evt.stopPropagation();
 evt.preventDefault();
 
 var files = evt.dataTransfer.files;
 
 if (files.length > 0) handleFileInfo(files);
}

function handleFileInfo(files) {
 var f = files[0];
 var output = [];
 output.push('<strong>', f.name, '</strong> (', f.type || 'n/a', ') - ',
     f.size, ' bytes, last modified: ',
     f.lastModifiedDate.toLocaleDateString());
     
 $("#fileinfo").html(output.join(""));
 
 var reader = new FileReader();

 reader.onload = function (evt) {
  document.getElementById("fileimage").src = evt.target.result
  };
 reader.readAsDataURL(f);
}

$(document)...});
This is where the event listeners (self-explanatory really) for the "dropper" element are defined. Since we have defined an area where we want users to drop files, then we have to link a bit of code to certain events, the code then being called to run. "dragover" and "drop" are predefined options, and I suspect many more exist for us to experiment with :).

It is recommended that you watch that video I linked to above, that's really how I learnt this.

function dragOver(evt) {...}
This is to prevent the default action from occurring when a user drops a file into the web browser. If you try this, then the browser will try to display the file. But we want to do much more than display the image.

function drop(evt) {...}
Same as above. But, when the user drops the file, we want to do something. We can call the handleFileInfo() straight away, but what I've done here is do a quick if() statement to check that there is something in the file to process.

function handleFileInfo(files) {...} This file processor.
  • output.push(..html(output.join("")); this takes the file the user has dropped, and reads certain parameters the belong to it. It then concatenates these and sends it to "fileinfo" - which we defined in index.html.
  • var reader... not sure, but calls FileAPI and gets it ready, if it isn't already :S.
  • reader.onload...readAsDataURL(f); ... more unknown :S. But in html speak, finds the "fileimage" element and then changes its' .src to evt.target.result (which is probably where the file was uploaded to)
    • readAsDataURL(f) VI!!. This is the method in which reader. reads the files. See FileReader for more info, scroll about half way down.
Done!  There is a lot of stuff here that I don't know about, but it has definitely given me a primer for HTML5 capabilities...and some ideas for my website (which is pretty dull to say the least!).

If you would like to download these two files and give it a go, get them here:
FileAPI_DnD_example.tar.gz
Many thanks! Till next time, Ciao!

Tuesday, December 13, 2011

Mv folders with spaces

So something has happened to my 320GB external HDD and I've started to get corrupt files :(. Not good. It is a few years old but I think that my best bet would be to remove everything and reformat it. This also gives me a chance to clean up all the shit and solve problems like how to move folders that have spaces in them - since spaces tend to cause a bit of trouble for programmers.

My solution is fairly simple, probably not the best and/or shortest, but the job is now done, and I can reformat my HDD.

The steps can be summarized as follows:

1) ls the directory with all the folders that you need to move and send the output to a .txt file. Before you ask why didn't I just move the parent folder? Well, to put simply, I had errors of some sort...so I had to do it the long way
2) Using 9 lines of python and the 'os' library, read the output.txt file and add "s to the start and end of every line. Close output.txt
3) Use nawk to read the updated output.txt file and move the folders (with spaces...grr) to the desired location.

Let's get started!

So here's the code and how I've done it. For the purpose of this example, I will compare the Music folder on my media drive and the Music folder on my desktop - each of which contain several sub-folders of artists. But if you want to just mv folders, then just skip some of the steps.

1)
~$ ls ~/Music > ~/computer-ls.txt

1a)
This is optional. Since I want to compare the contents of ~/Music to /media/Music and move only those files that are in ~/Music but not in /media/Music, do this step - use diff to compare the .txt files, grep > or <, cut off the > and < (to match folder names), and then send the output to a file:
~$ ls /media/Music > ~/media-ls.txt

~$ diff ~/computer-ls.txt ~/media.txt | grep "<" | cut -b3- > move.txt
~$ diff ~/computer-ls.txt ~/media.txt | grep "<" | cut -b3- > move2.txt

When using diff, the output is read such that which ever way the arrow is pointing, then that indicates that the string is in that .txt file but not in the other, i.e. using the code above, if I get output < Ramones, then I know that the Ramones folder is in ~/computer-ls.txt but not in media-ls.txt.

Two move.txt files need to be created because later, python cannot read from a file opened with the 'w' permission and vice versa.

If you wish, review the .txt files and the folders themselves to see if it is true about which folders are missing.

2) Skip this step - python not needed.
The python bit. Python should come installed on your Linux flavour, if not, apt-get install python :). Open a python cli, then run the following command using the .txt files we just created.
~$ python
>>> fread = open('~/move.txt', 'r')
>>> fwrite = open('~/move2.txt', 'w')
>>> for line in fread:
>>>     fwrite.writelines(str("\""+line[:-1]+"\"\n"))
>>> 
>>> fread.close()
>>> fwrite.close()
>>> quit()

The move2.txt file should now have the same folder names as move.txt, but will have "s at the start and end of ever line. "like this"

3) See update below.
Nawk bit. You should have done all this in the same directory, just don't forget to clean up :P. The last command uses nawk (a file scanner which can do a lot more!) to read the move2.txt file, and then run the mv command.

~$ nawk '{ system("mv -v " $0 " /media/Music/") }' ~/move2.txt

Make sure to give the correct file - the one that we changed.

Simple break-down (since I'm still an amateur) - if easier, maybe imagine nawk is like a 'for i in array/file/variable' command:
  • nawk > the nawk app
  • '{ command }' > everything inside the single quotes and curlies is what you want to do, spacing is critical here
  • system() > tells nawk to run it in termina
  • $0 > tells nawk to get the whole line. $1, $2, $3 etc. can be used to read only a single component of a line where the components may be separated by a space (grr). i.e. if the code above used $1 and a folder was called "Black Sabbath", then the output would be Black and we would fail to mv the folder.
Done! Since we used mv -verbose, we should be able to see the files being moved over.

Hope this helps! Till next time, Ciao!

Update:
Step 2) not needed. "s can be inserted in the nawk step as follows:
~$ nawk '{ system("mv -v \"" $0 "\" /media/Music/") }' ~/move.txt

Tuesday, December 6, 2011

Installing TweetDeck on Ubuntu Linux

This one is for all the Twitts out there looking to use a dedicated Twitter client for viewing their subs/lists/trends etc. While there are several clients available and native for Ubuntu (though I am yet to try them), TweetDeck gives a great interface with easy personalization. It also has an inbuilt URL shortener and update notification which can be set to show in the top-right corner...although this can be annoying if you follow a lot of Twit-a-holics (The type I like :D)!

This HowTo will show how to install TweetDeck and the AdobeAir package (which TweetDeck depends on) for Ubuntu. This install was done on kernel version 3.0.0-13.


1) Open up terminal, and direct to a folder where you want to work. I went to my ~/Downloads folder. Then, acquire the AdobeAIRInstaller with wget - it will download to the current directory that you are in. Use ls if you want to check that it is there. Change the permissions so that it can be executed. Execute it - you should get an Adobe window popup and ask you whether you want to install. Follow the options and after about 5 clicks it should be done. Remove the installation file (or keep it). Code is below:
$ wget http://airdownload.adobe.com/air/lin/download/latest/AdobeAIRInstaller.bin
$ chmod +x ./AdobeAIRInstaller.bin
$ sudo ./AdobeAIRInstaller.bin
$ sudo rm -rf AdobeAIRInstaller.bin

If you don't know, AdobeAIR is some sort of installer program. It is used when you want to install certain programs (that run Adobe I suspect...).

Navigate to the TweetDeck website and hit Download. The AdobeAIR window should popup. Follow the prompts and change the installation directory if so desired. Done!

Hope this helped. If AdobeAIR is not installed, then clicking on the TweetDeck Download button will not work, not matter how long you wait.

Happy Tweeting!

Monday, November 7, 2011

Gear...

Need to get in gear.

Knock it up, knock it up, knock it up!

Friday, October 28, 2011

Trembling Ambition

Waiting for my departure,
There's a place that I haven't been.
Waiting for the words to finish,
There's trembling in novocaine speak.

What did I see?
The world did turn and shed a tear.
Where did I dream,
The relic of a time only we could see?

And when I wailll...
By recognition and ample time,
Oh I don't refrain,
We've recovered from a trembling ambition.
And there's time to make haste.

It doesn't take years to uncover,
But many to build it up.
To see what's yet to come,
By forgetting what brought us here.

And when I trail...
I go on and on at you.
But don't let me fail,
It's ok that we are here.
It's ok, we're making memories.

(C) me, 2011

Friday, October 7, 2011

Lyrics: Bob Dylan - My Back Pages

I feel a breeze, the air it carries a sweet tenderness about it. It is not that which compels me to proceed, rather that which tells me how. There be many tales which remain untold, that require to transcend time. But it is the words of a well known man, which cite the reasons not to be bold (insert more appropriate word here).

Bob Dylan - My Back Pages

Crimson flames tied through my ears
Rollin’ high and mighty traps
Pounced with fire on flaming roads
Using ideas as my maps
“We’ll meet on edges, soon,” said I
Proud ’neath heated brow
Ah, but I was so much older then
I’m younger than that now

Half-wracked prejudice leaped forth
“Rip down all hate,” I screamed
Lies that life is black and white
Spoke from my skull. I dreamed
Romantic facts of musketeers
Foundationed deep, somehow
Ah, but I was so much older then
I’m younger than that now

Girls’ faces formed the forward path
From phony jealousy
To memorizing politics
Of ancient history
Flung down by corpse evangelists
Unthought of, though, somehow
Ah, but I was so much older then
I’m younger than that now

A self-ordained professor’s tongue
Too serious to fool
Spouted out that liberty
Is just equality in school
“Equality,” I spoke the word
As if a wedding vow
Ah, but I was so much older then
I’m younger than that now

In a soldier’s stance, I aimed my hand
At the mongrel dogs who teach
Fearing not that I’d become my enemy
In the instant that I preach
My pathway led by confusion boats
Mutiny from stern to bow
Ah, but I was so much older then
I’m younger than that now

Yes, my guard stood hard when abstract threats
Too noble to neglect
Deceived me into thinking
I had something to protect
Good and bad, I define these terms
Quite clear, no doubt, somehow
Ah, but I was so much older then
I’m younger than that now

Copyright © 1964 by Warner Bros. Inc.; renewed 1992 by Special Rider Music

Yeah...so as you can tell I've found lyrics, and they have imprinted on me. Nevertheless, I will see how many people I can share them with.

Ciao!

Sunday, October 2, 2011

md5sum for Ubuntu USB Installer

Hey all! Just a quickie to explain the importance of md5sum checking.

When using the Ubuntu Startup Disk Creator, making bootable USB thumb drives is straight forward. The .iso file which is used to make the thumb-drive however must meet a data integrity test using the md5 algorithm. Essentially, if you decide to download a Linux distro, you should (and up until now, I haven't been) check the md5sum and that it matches the string defined on the Ubuntu Website.

The method is quite simple and will save time in the longrun. A description and method for use of md5 checksum can be read here.

To check the integrity of the data via md5, open terminal, goto the location of the linux-distro.iso, and enter the following:
$ md5sum linux-distro.iso

This may take some time depending on your computer, but I'd say no longer than 2mins. Here is an example showing the output when checking the md5sum for the distro Ubuntu 10.10:
$ md5sum ubuntu-10.10-desktop-i386.iso
59d15a16ce90c8ee97fa7c211b7673a8  ubuntu-10.10-desktop-i386.iso

And if you cross reference with the Hash Site, you will see that there is consistency.

This post was made because I have just tried to boot Ubuntu 11.04 Live on my friends laptop and was getting SQUAHFS read errors.

A seemingly n00bish mistake, but we gotta learn somehow.

Until next time. Ciao!