Category Archives: php

unwatermarking images

I’ve started a website where I intend to sell thousands of products from a number of distributors through drop-shipping (the products go directly to the customer).

For reasons that I don’t understand, the distributors have watermarked their images, and don’t provide unwatermarked versions unless you’re an already well-established customer of theirs.

For the purpose of this demo, a watermark is a constant-colour “stamp” which is given opacity and pasted into the original image.

As I intend to be a good customer, I figured it would be okay for me to simply “unwatermark” the images.

There are a number of instructions online which show how to /fake/ an unwatermaking – by basically smudging the area where the watermark is.

However, as most watermarking appears to follow a single method, it is actually possible to simply reverse the process and remove the watermark, after a little trial and error.

Let’s consider an example. Here is an image, a stamp, and the merge of the two:

(original is here)

  • demo1
  • demo2
  • demo3

To reverse this, you need to know what algorithm was used to create the watermark, and what the original watermark was.

Most people use a fairly simple method to watermark their images:

The stamp is one single colour, usually gray (#808080 in RGB) which will be visible on images which are both light and dark.

The stamp is then given an opacity (30% in my case above), and pasted directly over the original image.

The formula for any particular colour channel (R, G and B) on any pixel is: C3=(1-p)C1+pC2, where p is opacity (0 to 1), C1 is the colour value for the original image, C2 is the stamp’s colour value, and C3 is the resulting image’s colour value.

To reverse the watermarking, you need to convert the formula to see what it is in respect to C1: C1=(C3-pC2)/(1-p).

As most stamps will be using a middle gray (#808080), you just have to guess at the opacity. .3 is a good start.

For some reason I’m not yet sure of, the code I came up with did unwatermark the image, but too much… the points where the watermark were, ended up being too bright. So I needed to add a darkening aspect, reducing the brightness of the result of the above calculation.

I’m not going to hold your hand if you can’t make this work, but here’s the code I ended up with (assumes the images are exactly 400×400 in size). The original should be ‘original.jpg’, and the stamp should be ‘stamp.png’ (with white where transparent pixels should be).

$p=.3; // opacity

$f1=imagecreatefrompng('stamp.png');
imagepalettetotruecolor($f1);
$f2=imagecreatetruecolor(400, 400);
$f3=imagecreatefromjpeg('original.jpg');
imagepalettetotruecolor($f3);

for ($x=0;$x<400; ++$x) {
  for ($y=0; $y<400; ++$y) {
    $rgb1=imagecolorat($f1, $x, $y);
    $rgb3=imagecolorat($f3, $x, $y);
    $r3 = ($rgb3 >> 16) & 0xFF;
    $g3 = ($rgb3 >> 8) & 0xFF;
    $b3 = $rgb3 & 0xFF;
    if ($rgb1==16777215) { // white. just copy
      $c=imagecolorallocate($f2, $r3, $g3, $b3);
      imagesetpixel($f2, $x, $y, $c);
      continue;
    }
    $r1 = ($rgb1 >> 16) & 0xFF;
    $g1 = ($rgb1 >> 8) & 0xFF;
    $b1 = $rgb1 & 0xFF;
    $r2=c($r1, $r3, $p);
    $g2=c($g1, $g3, $p);
    $b2=c($b1, $b3, $p);
    $c=imagecolorallocate($f2, $r2, $g2, $b2);
    imagesetpixel($f2, $x, $y, $c);
  }
}
imagejpeg($f2, 'unwatermarked.jpg');

function c($c1, $c2, $p) {
  $c=c1($c1, $c2, $p);
  $c3=$c-(255-$c)*.2;
  return $c3<0?0:(int)$c3; 
} 
function c1($c2, $c3, $p) {
  $c=($c3-$c2*$p)/(1-$p);
  return $c>255?255:(int)$c;
}

installing kv-WebME in CentOS 6

I’m setting up a new server and need to install kv-WebME in it. The previous instructions (for Fedora 16) were fine for an older version of WebME, but the most recent requires more uptodate packages.

So, first, we need to tell CentOS 6 to use more uptodate packages than are provided by default.

su -
rpm --import  http://apt.sw.be/RPM-GPG-KEY.dag.txt
rpm -ivh http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm

Now we need to install PHP (at /least/ 5.3), Apache, MySQL, etc.

yum install httpd mysql-server php php-gd php-mysql php-xml svn zip unzip

Add a user account for the website, and download the kv-webme repository

adduser webme
su - webme
svn co https://kv-webme.googlecode.com/svn/trunk/ kv-webme
chmod 755 /home/webme
exit

Now add the web configuration to /etc/httpd/conf/httpd.conf

NameVirtualHost *:80
<Directory /home/webme/kv-webme>
  AllowOverride All
</Directory>
<VirtualHost *:80>
  DocumentRoot /home/webme/kv-webme
</VirtualHost>

And finally, turn it all on.

service httpd start
service mysqld start
chkconfig --level 35 mysqld on
chkconfig --level 35 httpd on

That’s it!

Adding a trigger-based plugin to WebME

One of my clients has his own fork of WebME that he keeps current with the SVN version.

He mentioned a collision recently, where a hack he had written into the online store plugin was overwritten by updates.

So, in this post, I’ll demonstrate how to add a plugin that uses a trigger to run some code.

First, we define what needs to be done.

The client wants that when an order in an online store has been processed, an email is sent out to that client.

This immediately points out where the trigger point goes. The processing of orders is done in the file ww.plugins/online-store/verify/process-order.php, so we need to put the trigger in there as well, at the end of the OnlineStore_processOrder() function:

  Core_trigger('after-order-processed', array($order));

What happens at that point is that the CMS will check all plugins to see if there are any that have a trigger of the name “after-order-processed”, and if there are, then that trigger will be fired.

So, next we need to create the plugin. In fact, it’s so easy I’ll just write it straight out. I’m calling this one “DemoPlugin”, so we start by creating the directory /ww.plugins/demo-plugin”, and placing the file plugin.php in it:

<?php
$plugin=array(
  'name' => 'DemoPlugin',
  'triggers'      => array(
    'after-order-processed'=>'DemoPlugin_afterOrderProcessed',
  ),
  'description' => 'Sends an email after an order is processed',
);

function DemoPlugin_afterOrderProcessed($PAGEDATA, $order) {
  mail('kae.verens@gmail.com', 'subject line', print_r($order, true));
}

Simple!

Now, in order to do this, I edited one file which is part of the “official” WebME package, to add the trigger. If you find you need to do this, please contact me and tell me what you’re trying to do, and what you edited, so I can add it to the SVN version and not break your code in future releases.

installing WebME in Fedora 16

I got a new laptop today, and as I’ve still got work to do, I need to get the system up and running so it can install WebME.

Here’s a minimal instruction set for installing WebME on your Fedora computer.

As ‘root’, run this in a console:

yum install httpd mysql-server php php-gd php-mysql php-pear-Log php-xml svn zip unzip
echo "127.0.0.1 kvwebme" >> /etc/hosts

Then edit /etc/selinux/config, change “enabled” to “disabled” and restart your machine.

Login as your normal user, run this in the console:

mkdir ~/websites && cd ~/websites
svn co https://kv-webme.googlecode.com/svn/trunk/ kv-webme
chmod 755 /home/kae

‘su’ to ‘root’ again. Add this to /etc/httpd/conf/httpd.conf:

NameVirtualHost *:80
<Directory /home/kae/websites>
  AllowOverride All
</Directory>
<VirtualHost *:80>
  ServerName kvwebme
  DocumentRoot /home/kae/websites/kv-webme
</VirtualHost>

And finally, in the console again:

service httpd start
service mysqld start
chkconfig --level 35 mysqld on
chkconfig --level 35 httpd on

That’s it – your system is set up. From that point, just go to http://kvwebme/ and follow the instructions from there!

jQuery maskImage plugin

I had a need today to write some code which involved masking one image with another, dynamically.

There is no simple way to do this in JavaScript. The nearest I came to finding working code online that does it was edge.js, but that’s not free.

So, I wrote my own.

demo

Download: zip (25k), bz2 (24k)

In the demo, what’s happening is that an image such as this:

is being used as a mask for another image:

to create a masked image:

For Firefox and Chrome and other recent browsers, it works using pure JavaScript (even works on the iPhone).

For Internet Explorer (sigh) you need to do a little bit of server-side setup.

Basically, on the server-side, make sure you have PHP installed, with the iMagick extension, then make the ‘cache’ directory writable by the server.

To use, insert an image into your document:

<img id="image-id" src="an-image.png" alt="" />

And then apply the mask using jQuery:

$('#image-id').maskImage({src:"the-mask.png"});

Simple, innit! That’s a few hours of my own life dedicated to saving a few minutes of yours ;-)

new API for WebME

As I said in the last post, an API would be required to make the system more testable and more consistent.

I started straight away and wrote up something quickly. Over the next week, it solidified into something that appears to cover any needs that I have.

So here’s how the API works:

Requests are sent to a URL which is generated like this:

/a
[/p=plugin-name]
/f=function-name
[/other-parameters]

The plugin name is optional. Leaving it out means you want to call a core function.

Parameters can be added by adding /key=value pairs to the URL.

An example URL might be this:

/a/f=login/email=kae@verens.com

Sending that, with a POST parameter for the password, will log me in.

To log out, I can use this URL:

/a/f=logout

Simple!

Function Names

mod_rewrite is used to direct a request through a script which tears the URL apart into parameters.

If a p parameter is given, the function is named after the plugin, rewritten to match the WebME coding standard.

For example, if the URL is /a/p=comments/f=editComment, then the “comments” part is rewritten as Comments, and ‘_’ and “editComment” are appended to form the function name “Comments_editComment”, which is called and the result returned to the browser.

For double-barrel plugin names, such as “image-gallery”, the name is rewritten to “ImageGallery”.

If no p parameter is given, then the request is a core function, and “Core_” is prepended to the function name.

For example, the login URL above, /a/p=login calls the function Core_login.

If a function name begins with “admin”, it is an admin function (see below for more on this).

File names

If no plugin name is supplied, then the core API file, /ww.incs/api-funcs.php is loaded. This contained common API functions that might be used by any core script or plugin.

If a plugin name is supplied, then the API file is expected to be located at /ww.plugins/plugin-name/api.php for common functions, and /ww.plugins/plugin-name/api-admin.php for admin functions.

For core functions, common functions are at /ww.incs/api-funcs.php and admin functions are at /ww.incs/api-admin.php

Security things

Having a central point for RPC means that we can apply security rules in one place and know that they cover all scripts. Before-hand, I would sometimes come across scripts and realise that they were open for abuse if someone knows that magic URL incantation. I would silently curse myself or whoever had written the script and fix it up. Now, though, having one single point of entry means I can secure everything at once.

If a function name starts with “admin”, then the script checks to see if the user is logged in and is a member of the administrators group. If not, the API will return an error. It’s as simple as that!

Of course, this doesn’t stop abuse by people that are logged in as admins or who are victims of XSS, but it helps stop a few problems caused by developers not noticing their scripts were open to use by anyone at all.

Conclusion

So now, when people are creating new plugins for WebME, the following could be used as a bare-bones directory structure:

/ww.plugins/plugin-name/plugin.php    details, server-side functions
/ww.plugins/plugin-name/api.php       common RPC functions
/ww.plugins/plugin-name/api-admin.php admin RPC functions
/ww.plugins/plugin-name/admin.js      admin scripts in JS

testing KV-WebME

I’ve been working on my CMS for about 10 years. It’s monstrously huge (41,000 lines, not including external libraries), and for most of those 10 years, I’ve been too busy building it to concentrate on niceties such as comments, testing, code formatting, etc.

This has caused problems in the past. As most programmers know, when you change any one thing, it has a ripple effect and can break things in places that don’t seem obvious at all.

Recently I’ve been remedying this. I’ve been religiously using PHPCS to make sure my code is neat and consistent, and I’ve started writing a test suite.

The most difficult part of the testing is that the CMS is composed of many separate technologies. If it was just a plain old HTML and PHP application, then PHPUnit would be enough, or maybe Selenium.

The problem is, though, that the system uses a large amount of AJAX – especially in the administration areas. No single testing system would do it all.

Another problem has to do with AJAX itself. In jQuery, you can speak to the server by writing something like this:

$.post('/a/server/script.php', {
  "id": 2
}, function(res) {
  // do stuff
}, 'json');

This makes it incredibly simple to speak to any server-side script at all on the server, and promotes it. It becomes tempting when writing new functionality to build new server-side scripts specifically for the new client-side stuff.

This has the effect that there is no single point for RPC (remote procedure calls) which can be tested, making it very difficult to be sure you have covered all potential problems.

To help solve this problem, I’ve recently started converting WebME’s coding style so all RPC is done through a single API (application programming interface) script.

This has a few extra effects which are beneficial:

  • Having a single point of entry into the system makes it easier to secure it.
  • Having an API promotes the construction of a solid method of adding functionality to it – there’s no need to start from scratch anymore, potentially building disparate scripts that are hard to abstract. Instead, it’s now easy to force the code to match a minimum spec.
  • APIs tend to have specific rules for how parameters are passed into it, making it easier to remember what the right parameters are when writing new client-side code. Also, it makes it easier to “guess” what the right parameters are if you’ve forgotten.

The main benefit, though, is that it makes it much easier to test. The URL of the API always stays the same, and the only thing that changes is the parameters sent to the URL. Previously, each separate script would have a different URL and could have any parameter scheme at all.

So, currently, I’m writing tests that use the API directly, speaking to the server directly through URL calls. After I’ve finished writing all of those (hah! if ever), I can get on to testing that JavaScript.

growing up

For a long time, whenever I did something that I thought was interesting, I would write it in an article.

I don’t write as much as I used to. Not because what I’m doing is not interesting, but because it’s taking a lot longer now to complete the interesting jobs, now that they’re basically full projects and not just little snippets here and there.

As an example, we’re doing some interesting work over in the KV WebME project. The most recent is an upgrade to image galleries allowing the gallery layouts to be defined using templates, instead of saying “you want layout 1, or layout 2?”. This work is then also used in the products plugin to let people sell images in their online stores.

There are a number of bits in that project that deserve full posts themselves, but as I basically commissioned the piece and got others to do the work, it’s no longer mine to describe. For me, the cool little tricks are now just a smaller part of a bigger picture.

The bigger picture right now is 20eu.com, where you can create your own online store within literally minutes for only €20 (compare that to the “free” getting business online project, which doesn’t have an e-commerce aspect).

It’s now harder for me to write about, because there are no longer single cool aspects that I can point to that can be re-used by other people.

I was walking to work today with Conor (an employee), discussing stuff along these lines, and these points stood out:

  • In the beginning, I was a programmer, and every task had something new to me but nothing I could write about that would interest experienced programmers.
  • After a few years, I was a good programmer, and I did less tasks, but they were larger, and there were often aspects to them that were brand new, so I ended up being one of the first to build them (it helps that my field is Ajax, which is basically new-born).
  • And now, I’m tired of being just a programmer and have started branching into managing other programmers. I’m more interested now in getting full projects done than in the nitty-gritty.

Unfortunately, this means there is less to talk about that is even vaguely techie. I feel like I’m shifting focus into marketing and project management.

Ick!

On the plus side (for me), it means that eventually, I’ll have enough resources that I can get the projects done that I’ve always wanted to do.

So, I plan on starting to write about the business end of my work.

Don’t worry – I’ll categorise it correctly, so if you’re only interested in my PHP or Linux posts, then just change your reader settings to only read from those RSS feeds.

What I’ve been up to

Being self-employed is hard work!

Naive person that I am, I thought it would be easy enough – I get to work on my own ideas all day long, occasionally selling something to customers who are happy every time.

Of course, that’s not true.

I spend a lot of my time working on jobs for my previous employer, and some other clients that have known me for years. The large pool of new clients that I expected would magically appear, never magically appeared.

Of course, it’s not all doom and gloom.

Being out on my own has taught me quite a lot, and in a very short time.

  • Cash is king – there’s no point having a huge job which may potentially pay you thousands of euro in two months, when you need the money right now to go buy food for the house.
  • Advertising is not easy! I hate to pester, so advertising is not a natural thing for me, but it’s tricky to get new people to come in and buy from me if they don’t know where I am. Especially if they don’t know whether to trust my work! Conveying trust in ads is not a very easy thing to do.
  • Word-of-mouth is a brilliant thing. It is much easier to sell to someone if they’ve already been half-sold by their friends.
  • Low prices don’t always pull people in. Even though I charge about a fifth of other local web designers, I think I must also be getting only a fifth of the customers ;-)
  • Salary is a wonderful thing, when it’s someone else’s job to make sure it gets paid.

Of course, there are also the upsides.

I get to work on my own projects without worrying that they my conflict with the company’s plans. Basically, I am the company, so anything I want to work on is the company plan.

To that end, I’ve created 20eurowebsites.com, a site-creator which is built on my kvWebME CMS (open source, PHP – download it yourself if you’re techie!). €20 to buy a website (including the domain name), and €10 per month hosting after that.

I have other plans in the works as well, such as a local odd-jobs finder which has a pretty good twist, and a free face-book-like chat application which people will be able to add to their own websites with just a few keystrokes.

multi-tenanted CMS architecture

Last week, I did a talk at the Dublin Google buildings titled “Multi-tenanted CMS Architecture using PHP”.

Here are the slides that I used:

While talking with Google’s Brian Brazil, he explained that it is actually more efficient to use one database and many separate tables, than to separate each installation into a separate database, so one point I made (that KV-WebME uses separate databases per site) will change in the future.

I think the talk went down well, by the number of questions afterwards.

Last year, I gave a similar talk, and made the mistake of including way too much PHP in it – I had assumed that the audience would be composed of PHP developers. This year, there is just one slide of PHP, and that’s just to illustrate one possible way to build a proxy config.

Lesson’s learned for this time:

  • Talk slower. When I’m explaining something, I tend to try to get as much in as possible, so speak very fast. This makes it hard to hear what I’m saying.
  • More pictures, less words!
  • Stats. Some of the questions were around how efficient certain parts of the method were – particularly on the overhead of piping a file through a script as opposed to simply delivering it via Apache. I need to come up with numbers for that.

Overall, I was happy with this presentation.