Bambi Twins
Bambi-Editor comes in two
build flavors: Desktop and Web Start.
If you're a regular user that wants to have fun with images,
save them to a computer and maybe print them, you want to
download
and install the desktop edition. If you're a website owner or developer
that wants to give end end users ability to upload images specifically
cropped and/or scaled to your requirements, you want Java Web Start edition.
Upon each release, Bambi dev team distributes both editions
simultaneously. They're both released to Sourceforge. Desktop
is available for a traditional download, Web Start is
available as a live JAR that can be
linked to via JNLP.
Feature-wise they are identical, but they are configured differently.
# codebase /bambi-editor
# compiles and builds desktop distribution
mvn clean package -P app
Web Start build (below) packs dependencies differently, and excludes
configuration because it needs to be externalized. You never
have to execute this build because you can link to our
latest JAR instead.
# codebase /bambi-editor
# compiles and builds web start distribution
mvn clean package -P ws
In addition, Web Start build provides for custom splash
screen and external configuration. You want to either
execute this build with your own webstart configuration,
or somehow (Ant, manually, etc) generate config JAR similarly to how this build
does it.
# codebase /bambi-webstart
# compiles webstart JAR and config JAR
mvn clean package -Djnlp.host=bambieditor.sourceforge.net -Dupload.dir=
So You're a Web Developer?
To run Bambi-Editor as JWS on your website you need to
provide a JNLP (Java Network Launching Protocol) script. In
that script you will reference your own configuration JAR,
which must include
configuration file and (optionally) any
custom plugins you may have written.
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="http://bambieditor.sourceforge.net/bambi/" href="bambi.jnlp">
<information>
<title>Bambi Editor</title>
<vendor>mrazjava</vendor>
</information>
<resources>
<property name="jnlp.packEnabled" value="false"/>
<!-- <property name="jnlp.bambieditor.splash-title" value="<html><h1>Custom Title</h1></html>" /> -->
<!-- Application Resources -->
<j2se version="1.7+" href="http://java.sun.com/products/autodl/j2se" initial-heap-size="128m" max-heap-size="1024m" />
<jar href="bambi-config-0.9.1.jar" download="lazy" />
<extension name="core" href="http://bambieditor.sourceforge.net/bambi/bambi-core.jnlp"/>
</resources>
<application-desc
main-class="org.zimowski.bambi.editor.BambiApp"
progress-class="org.zimowski.bambi.webstart.WebStartProgress" />
<update check="always" policy="always"/>
</jnlp>
Line 14 references your config JAR, which must
be signed. Line 15 points
to our latest compiled and signed Bambi-Editor JAR. Since
line 15 links to a prepared JAR, you can host Bambi with very
little effort! Neat, isn't it?
An example of custom configured BambiEditor running of a different domain
can be seen on my personal
server.
There you can launch bambi with custom configuration but core (extension) still
pointing to our sourceforge base.
Of course, if you want you can download source code and build
entire thing yourself without linking to our JAR. We assume, that
if you're that adventurous you know what you're doing.
Singing the Bambi Song
When user uploads a photo from Bambi-Editor, server processing script needs to sing to
the same tune that Bambi does. It is
not required
to use any particular technology, it just needs to comply
with Bambi's upload plugin protocol. Bambi-Editor ships with
two upload plugins out of the box, which should cover most
needs:
They both get end-user's image to your server, though the form post plugin is by far the
more flexible of the two. FTP plugin does
not require a server side script, form
post
does. It is the form post plugin ability to communicate with a script that makes it so powerful and
versatile. In this article we focus on explaining how to accept Bambi image upload via
form post with PHP server script saving a photo to MySQL blob.
In general, the form-post data flow scheme is as following:
On this demo website image upload is saved by PHP script into MySQL blob.
FTP upload scheme is similar, except there is no script, so image is always
saved to server's filesystem.
So the scenario is this: Your end users play with their image applying various Bambi filters, then
when ready upload it over internet targetting a URL you configured. Bambi handles all the latency
issues so your user sees a real-time progress on the UI.
Your processing script (URL) is essentially free to do anything it wants with the image. Typically
a script will save the image, either to a local filesystem
or a database blob, but there is nothing precluding it from doing other things like sending it via e-mail or posting to a twitter account.
Possibilities are endless. Here is a PHP script this demo site uses to process image upload via form post:
<?php
include "include/db.php"; // your db configuration
//
// Form post upload processor that requires explicit authentication.
//
// Response Protocol:
// KEY|VALUE - one line, lines can be in any order
// Keys:
// STATUS - OK or ERROR, required
// RECEIVED - number of bytes received, required
// PROCESSED - number of bytes actually processed, required
// DATE - server date/time when request was processed, optional
// MSG - message from server (error or info), optional
$uid = 0;
$email=$_SERVER['HTTP_USER_ID'];
$pass=$_SERVER['HTTP_USER_PASS'];
$expected_bytes = (int) $_SERVER['HTTP_STREAM_SIZE'];
$f = $_FILES['filename']['tmp_name'];
$fsize = filesize($f);
$p = $_GET['p'];
if($email != null && $pass != null) {
$sql = "select id from t_user where email = '{$email}' and password = '{$pass}'";
if(!$result = $db->query($sql)) die($db->error);
if($result->num_rows == 1) {
$row = $result->fetch_assoc();
$result->free();
$uid = $row['id'];
}
else {
echo "RECEIVED|$fsize\r\n";
echo "PROCESSED|0\r\n";
echo "STATUS|ERROR\r\n";
echo "MSG|Invalid Login\r\n";
echo "DATE|".date("Y-m-d H:i:s");
return;
}
$data = addslashes(fread(fopen($f, "r"), $fsize));
if($expected_bytes == $fsize) {
$sql = "select count(*) as c from t_pic where user_id = $uid";
if(!$result = $db->query($sql)) die($db->error);
$row = $result->fetch_assoc();
$result->free();
if($row['c'] > 0) {
$sql = "update t_pic set pic{$p} = '{$data}' where user_id = {$uid}";
}
else {
$sql = "insert into t_pic (user_id, pic{$p}) values ({$uid},'{$data}')";
}
$db->query($sql);
echo "RECEIVED|$fsize\r\n";
echo "PROCESSED|$fsize\r\n";
echo "DATE|".date("Y-m-d H:i:s")."\r\n";
echo "MSG|{$p}\r\n";
echo "STATUS|OK";
}
else {
echo "RECEIVED|$fsize\r\n";
echo "PROCESSED|0\r\n";
echo "STATUS|ERROR\r\n";
echo "MSG|byte mismatch: [expected $expected_bytes, received: $fsize]\r\n";
echo "DATE|".date("Y-m-d H:i:s");
}
}
else {
echo "RECEIVED|$fsize\r\n";
echo "PROCESSED|0\r\n";
echo "STATUS|ERROR\r\n";
echo "MSG|Incomplete Login Info\r\n";
echo "DATE|".date("Y-m-d H:i:s");
}
$db->close();
?>
The script above verifies authentication credentials entered by the user into Bambi-Editor, and
saves the image to a database blob if user authenticated correctly. Notice the script above will reject an image if user authentication fails. In our demo
implementation user password is stored securely as MD5 digest:
Passwords stored in our live demo database are unreadable, secured by MD5.
But wait... In the PHP script we
don't see md5('') function invoked in the SQL on the {$pass} value that came from $_GET. That's because Bambi-Editor is
capable of encrypting values before they're sent over a wire! By the way, the encryption algorithm is a
plugin and Bambi supports more than just MD5. So by the time password reaches the script it's
already been hashed and we can simply compare both strings.
Here is a database used by the upload script above:
-- MySQL dump 10.13 Distrib 5.5.31, for debian-linux-gnu (x86_64)
--
-- Host: localhost Database: bambi
-- ------------------------------------------------------
-- Server version 5.5.31-0ubuntu0.13.04.1
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `t_pic`
--
DROP TABLE IF EXISTS `t_pic`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `t_pic` (
`user_id` int(11) NOT NULL,
`pic1` mediumblob,
`pic2` mediumblob,
`pic3` mediumblob,
`pic4` mediumblob,
`pic5` longblob,
PRIMARY KEY (`user_id`),
KEY `fk_user_id` (`user_id`),
CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `t_user`
--
DROP TABLE IF EXISTS `t_user`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(45) NOT NULL,
`password` char(32) NOT NULL,
`date_created` datetime DEFAULT NULL,
`fname` varchar(20) DEFAULT NULL,
`lname` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email_UNIQUE` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
-- Dump completed on 2013-06-03 15:00:12
We designed upload capabilities for five images per user
account, but implemented the actual demo with first four
disregarding pic5 longblob.
Closing Remarks
Enabling Bambi-Editor on your website is easy. All you need are the following components:
- A JNLP script pointing to your own config JAR and Bambi core release.
- Your own signed configuration JAR. In it you can include your custom plugins if you wrote any.
- Your upload processing script (if using formpost). You can use any language for this purpose. In our exaple we used PHP.
- Optionally, a database if you decide to save uploaded images into a blob.
While we plan to enhance Bambi-Editor with additional upload strategies
(Socket Uploader for example) - you could write your own and contribute to
us. We feel that plugins such as FacebookUploader, TwitterUploader
and other social networking in nature will make Bambi even more
useful!