Category Archives: Nerd Stuff

Bulk Image Processing: How to shrink a bunch of images using iPhoto on OS X

Here’s a real quick tip. Let’s pretend that you took a bunch of nice big photos with your nice digital camera. But your friend wants copies… and you can’t email them because the files are huge! How do you shrink down hundreds of images quickly? Let iPhoto and Mail help…

See the video for this tip in action, or follow these simple steps:

1. Open iPhoto and highlight the images you want
2. Choose to Mail the photos by clicking the Mail icon at the bottom of iPhoto.
3. Choose the size that you want for your new images.
4. When the new Mail message opens up, you could actually send the message at this point (assuming that Mail is configured correctly to send and receive messages), OR you can select all, then drag the message contents over into a desktop folder.
5. You can zip up the contents of the Desktop folder and be done!

Add Watermarks to Photos Online for Free with PicMarkr

Any time you put a photo on the Web, you run a risk that someone will claim it as their own. If you are okay with this, then please ignore this post. However, you can easily add protection against image theft by adding a watermark.

Sure, many photo editing programs (such as Photoshop, GIMP, Picasa) can add watermarks to images, but in a pinch you can just use your browser to upload photos to PicMarkr and easily add a watermark online.

Adding watermarks using PicMarkr is a simple three-step process.

Step One – Upload

First, you need to get your image(s) into PicMarkr. Using their browser upload tool, you can upload up to five pictures at once, with a total file size up to 25 MB.

PicMarkr - Upload
PicMarkr - Upload

If you’re a Flickr user, you can also grant PicMarkr permission to login and grab images directly from your Flickr account. Sweet.

Step Two – Set Watermark

Once PicMarkr has your image(s), it’s time to create and set your watermark. You have three choices here:

  1. Text watermark
  2. Image watermark
  3. Tiled watermark
PicMarkr - watermark types
PicMarkr - watermark types

Text Watermark

To add a text watermark (the default choice), just type your text, choose a preset type, and pick an alignment position.

Here’s a picture of a goat on a car that I took in Greece this past summer. Crazy animal. Note the text watermark at the bottom.

Goat hood ornament

Image Watermark

To add an image watermark, just upload your own logo and choose an alignment position.

I can haz learner's permit?
I can haz license?

Tiled Watermark

The third option is to add a watermark tile. You can choose to stick to text (default), or use a picture as the watermark.

And of course, here’s our crazy goat with a watermark tile.

Bah, Bah, black goat?

Step Three – Save

Now that your watermark is applied, all that is left is to save your new image. You can either download directly to your computer or choose to upload to your Flickr account. That’s it. You’re done.

While PicMarkr is free, I should mention that they offer a Pro version (Windows only at the moment) that has some advanced capabilities, including the ability to replace photos on Flickr.

My only real complaint about PicMarkr is that if you mess up, you cannot simply go back a step and try again. You have to go back and upload the original image again. Frustrating.

Still, it is hard to complain when the free version works very well, and PicMarkr’s free capabilities are impressive. The entire process is fast, the built-in presets are plentiful, and most importantly, it’s easy to use.

Checking to See if Packages are Installed in PHP or Perl

I have this love/hate thing with open source technology. It’s great that it’s free, bugs are openly discussed instead of hidden away, and ultimately I think the open source technologies are more robust.

But here’s what always gets me: the packages and their dependencies.

Perl

At the bash prompt, you can type:
perl -e 'use Some::Package'

If the package is installed, nothing will happen. The one line script executes without complaint. But if you DON’T have that package installed, you’ll get an error like this:
Can't locate Some/Package.pm in @INC (@INC contains: /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi
[...]
/usr/lib/perl5/5.8.8/i386-linux-thread-multi /usr/lib/perl5/5.8.8 .) at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

If that’s the case, you need to find and install that package. With Perl, the way to go is to get familiar with www.cpan.org — yes, it’s a fugly site, but you can search for packages and read up on them. If you want to download them, I recommend using the CPAN command line tool. You run this utility by simply typing cpan on the bash command line. Take the time to understand this utility! It will save you SO MUCH TIME.

PHP

PHP is nowhere near as verbose as Perl when it comes to error messages and debugging; it’s also a bit more mysterious when it comes to its package structure. You can get a lot of information by examining the output of the phpinfo() function. Simply write following script and hit it with a web browser:


<?php phpinfo(); ?>

On the command line, you can use rpm to see if a specific package is installed… however, good luck guessing what the package name is. For example, here you can check the version of the GD graphics library:
rpm -q php-gd
If the package is installed, the result should be something like:
php-gd-5.1.6-20.el5_2.1

You can also have a look in the php module directory. For Linux systems, it’s often here: /usr/lib/php/modules/

Search the File System

If you’re still frustrated, you can search the file system for the file — modules are FILES… they live SOMEWHERE. In Linux, you can use the find command:
find /path/to/start/search -name 'name_of_file'
E.g. to search for myfile.txt in the current directory or beneath, you’d type this:

find . -name myfile.txt

All the Linux file name metacharacters are valid, e.g. “*.txt” to search for all text files. The path can also be specified as any valid pathname, e.g. “~/” to refer to the current user’s home directory.

It’s a bit messy in there, but hopefully this helps you evaluate a system to see if your scripts or pages will actually work!

Keep Your Address Book in Sync with Dropbox (Mac OS X)

Disclaimer: some users have reported that this method does not work properly. Rest assured that it works, but I only recommend it for people comfortable with the Terminal. There’s a lot of room for error.

Please back up your Address Book before attempting this method. I am not responsible for lost data. Please see the comments below for further commentary.

Here is a little tip for you Mac users out there. We have written about the awesome, cross-platform Dropbox service before (here and here), and while it’s great for keeping ordinary files and folders in sync across the Internet, there are a few more clever uses for it.

With a tiny bit of command-line magic, you can easily keep your Mac OS X Address Book backed up online and synced to other Macs. Here’s how:

Preliminary Steps

First of all, download and install Dropbox on any OS X machines that you wish to sync. Finished? Excellent!

Next, go ahead and make a backup of your Address Book (optional, but strongly recommended). Just go to File → Export → Address Book Archive….

Keep that export handy in case things go wrong.

Link Address Book to Dropbox

Here’s the fun part. To make this process work, Address Book needs to be able to save data to your Dropbox folder. At present, Dropbox can only sync ONE folder (and everything in it). So, you see the problem? Address Book keeps all its data inside ~/Library/Application Support/AddressBook, and we need to trick Address Book into saving to your Dropbox folder.

Symbolic Links to the rescue! We can easily fool Address Book by creating a symlink.

Step 1 – First, we’re going to move the Address Book data files to your Dropbox folder. Make sure Address Book is closed. Launch Terminal (in your Utilities folder), and assuming your Dropbox folder is inside your Home directory, issue this command:

mv ~/Library/Application\ Support/AddressBook ~/Dropbox/

Step 2 – Now, create the symbolic link. The format is ln -s [destination] [name of file or folder]. The syntax does not change as to whether the link is to a file or a folder. Still in Terminal, type:

ln -s ~/Dropbox/AddressBook/ ~/Library/Application\ Support/AddressBook

That’s it. You’re done. Try launching Address Book and make sure your contacts are still there. Now when you add a new contact and it, you should see Dropbox update as well. Notice the tiny, green Dropbox check marks on my AddressBook linked folder:

Adding Other Macs

To add another OS X machine to the mix, just repeat these steps (except for the first mv command). In short, just install Dropbox, make sure Address Book is closed, and then:

  1. Delete the AddressBook folder from ~/Library/Application Support
  2. Create the symlink (ln -s ~/Dropbox/AddressBook/ ~/Library/Application\ Support/AddressBook)

There you go. Address Book will stay syncronized and backed up online.

Stealth Submit: Using AJAX to Save Form Data Without Submitting the Form

Ah, this is sneaky. You may think that a web site can’t read form fields until you hit the submit button, but this is not the case. Using AJAX, a site can read form data at any time. This could be used for nefarious purposes, but I’m presenting here for two reasons: 1) to let people know that it can be done and 2) to show people how to do it for legitimate purposes. What’s a legitimate use of this? Logging, mostly… a lot of work goes into studying why users may fill out only the first page of a form. If you log the data regardless of whether a user clicked submit, you can study user behavior and possibly improve your form.

This tutorial assumes the following: you have a web server running PHP 5 (or greater) and MySQL 5 (or greater) with the mysqli extension installed. There are several parts to how this works:

1. savedata.php: A processing page that grabs posted variables (e.g. savedata.php?variable=value).
2. db.php: A database interface file (usually contained above the document root, contains passwords and save logic).
3. index.php: The HTML page containing the form.
4. The prototype JavaScript library. This is a very handy library that’s pretty easy to use.

Here’s an image showing how these files are organized in their folder structure. /html is the document root of the site: all browser requests are directed in there. /lib is above the document root… only PHP can make calls inside that folder. That’s were we put our database connection logic, including usernames and passwords.

Folder structure used for Stealth Submit Files
Folder structure used for Stealth Submit Files

The files used in this demo are listed below, but because scripts tend to get buggy when they’ve undergone conversion to/from html-entities, I’m zipping up the files and uploading them here.
Stealth Submit Sample Files.zip

You should be able to unload the html and lib directories to your web server. Point your DocumentRoot at the html directory; be sure to run the SQL commands included at the top of the db.php file so your database looks the way that this script expects it to.

For the use of visibility, the contents of these files is included below:

html/savedata.php : the PHP Page that grabs and stores variables


<?php
/*
Test this page by hitting it in a browser with variables:
http://your_domain/savedata.php?first_name=Bart&last_name=Simpson&age=11&home_town=Springfield&job=Punk

*Add &debug=1 to the url to print out verbose messages.
*/

include_once($_SERVER['DOCUMENT_ROOT'] . "/../lib/db.php");
$debug = $_REQUEST['debug'];
$debug_msg ="<p>The following variables were passed:</p><hr/>";

// Harvest all form data: this works for posts and gets.
foreach ($_REQUEST as $var => $value) {
$debug_msg .= "<b>$var</b>: $value<br/>";
$form_data[$var] = $value;
}

if ($debug) {
echo $debug_msg . "<hr/>";
}

$result = save_user_data($form_data);

if ($debug) {
if ($result) {
echo "Data saved successfully. Id: $result";
} else {
echo "Error saving data.";
}
}

?>

lib/db.php : Here’s the Database Interface Page


<?php
/*
Contains database handle (username/password) and saving functions

Here's the table definition for the table used in this demo:

CREATE DATABASE ajax_demo;

CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`first_name` char(64) default NULL,
`last_name` char(64) default NULL,
`age` tinyint(3) default NULL,
`home_town` char(64) default NULL,
`job` char(64) default NULL,
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM;

GRANT ALL PRIVILEGES ON ajax_demo.* TO 'peter'@'%'
IDENTIFIED BY 'abc123';
*/

// Test regex's here by uncommenting this line and executing this file.
// echo get_name_regex('Bob');
/*-------------------------------------------------------------------------
DEFINE Database constants here
---------------------------------------------------------------------------*/
define("DATABASE_HOST", 'localhost');
define("DATABASE", 'ajax_demo');
define("DEFAULT_USER", 'peter');
define("DEFAULT_USER_PASSWORD", 'abc123');

function connect_db ($user = DEFAULT_USER) {
/*
INPUT: $user
This function allows for multiple handles to be called, e.g. handles for
read-only, write-only, etc. Each user has its own permissions.
mysqli format is mysqli(DATABASE_HOST, USER, PASSWORD, DATABASE);
*/
switch($user) {
case DEFAULT_USER:
$link = new mysqli(DATABASE_HOST, DEFAULT_USER, DEFAULT_USER_PASSWORD, DATABASE);
break;
}

return $link;

}

/*-------------------------------------------------------------------------*/
function save_user_data ($input) {
/*
INPUT:
Hash with values from form, e.g. $input['first_name'].
OUTPUT:
id from database if successful insert; otherwise null.
*/

$link = connect_db();
/* check connection */
if ( mysqli_connect_errno() ) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}

$sql = "INSERT INTO user
(
first_name,
last_name,
home_town,
job,
age
) VALUES (
?,
?,
?,
?,
?
)";

$statement = $link->prepare($sql);

if (!$statement) {
printf('Error - SQLSTATE %s.\n', mysqli_sqlstate($db_connection));
exit();
};

// Filter data (regex's, validate, etc)
$first_name = get_name_regex($input['first_name']);
$last_name = get_name_regex($input['last_name']);
$home_town = get_name_regex($input['home_town']);
$job = get_name_regex($input['job']);
$age = get_integers_only_regex($input['age']);

// Bind-parameters: s=string, i=integer, d=double, b=blob
$statement->bind_param('ssssi', $first_name, $last_name, $home_town, $job, $age);

$statement->execute();

if ($link->error) {
echo $link->error;
}

if ($link->insert_id) {
$result = $link->insert_id;
}

echo

$link->close();

return $result;
}

/*====== DATA FILTERING and VALIDATION =============================*/
function get_name_regex ($input) {
$pattern = '/(;|\||`|=|--|\/|\.|>|<|&|^|"|'."\n|\r".'|{|}|[|]|\)|\(|[0-9])/i';
$input = preg_replace($pattern, ' ', $input);
return trim(ucfirst($input));
}

// Given any input, we only want a valid integer here, e.g. 2.24 --> 2
// Specify the length desired.
function get_integers_only_regex ($input, $len = 100) {
// $input = (int)$input; // typecast will fail if you have a zip w/ a leading 0, e.g. 09921
if ($len > 0) {
$pattern = '/\D/';
$input = preg_replace($pattern, '', $input);
$input = substr($input, 0, $len);
}
return $input;
}
?>

html/index.php : the HTML Page Containing the Form

<html>
<head><title>Stealth Submit</title>

<script src="/js/prototype-1.6.0.3.js"></script>
<script language = "Javascript">
function saveData() {
new Ajax.Request('savedata.php', {
method: 'post',
parameters: {
// $('form_id').serialize(true)
first_name: document.getElementById('first_name').value,
last_name: document.getElementById('last_name').value,
home_town: document.getElementById('home_town').value,
age: document.getElementById('age').value,
job: document.getElementById('job').value
}
});
}

</script>

</head>
<body onunload="saveData()">
<form id="form_id" method="post" action="action.php">
First Name: <input type="text" id="first_name" name="first_name"><br/>
Last Name: <input type="text" id="last_name" name="last_name"><br/>
Age: <input type="text" id="age" name="age"><br/>
Hometown: <input type="text" id="home_town" name="home_town"><br/>
Job: <input type="text" id="job" name="job"><br/>
<input type="submit" value="Submit" />
</form>

<a href="http://www.google.com/">Arbitrary Other Page... FORM NOT SUBMITTED</a>

</body>
</html>

FREE Book – Definitive Guide to Linux Network Programming (PDF)

To continue in the spirit of free products, Apress.com is giving away digital downloads of The Definitive Guide to Linux Network Programming.

The book has a list price of $49.99, and is available for free download here.

Update: the download link appears to be down on Apress right now (due to massive traffic). Here is a temporary download link.

For those of you who don’t like staring at computer screens too long, you can purchase a hard copy on Amazon for $35 (Amazon link). It has pretty good reviews on Amazon so far, so this 400-page book is certainly worth adding to your arsenal.

Enjoy.

ZoneAlarm Pro 2009 – Free Download Today Only

As mentioned yesterday, Check Point software is celebrating its 15th anniversary today, and YOU get to reap the benefits. Today only, you can download ZoneAlarm Pro 2009 for FREE.

What you get: A professional firewall, plus anti-spyware and ID protection. Note – this is a subscription valid for one year ($40 value).

How to get it: The download link is right below. It will expire on 19 November 2008 at 6 AM PST.

http://download.zonealarm.com/bin/free/sum/index.html

Suggested alternative: If you don’t care for ZoneAlarm or if you missed this deal, you could try Comodo Internet Security instead (free). Look for an upcoming review here soon.