Rotate Your Movie

I have received by e-mail a rotated video in the ‘flv’ format. The video was supposed to be a vertical one, but it turned out to be horizontal, that is ROTATED. So, I wrote a little program to rotate it back using libming.
There are two things to take care of when processing the input FLV:

  • The video stream.
  • The sound stream.

Both can be taken from the FLV file.
The code is written in C++, but can be translated easily into PHP. Following is the code:

#include <iostream>
#include <mingpp.h>

using namespace std;

int main(){
  const char *flvFile ="/path/to/inputVideoFile.flv";

  // Get the video stream from the file. The input file can be in the FLV format.
  SWFVideoStream *stream = new SWFVideoStream(flvFile);

  SWFMovie mov (9);  // Create the movie object.

  // The method 'add' returns a display item.
  // Display items can be rotated, transformed, etc.
  SWFDisplayItem *di=mov.add(stream);  

  // Sound streams are taken from a file object. 
  FILE *soundFD = fopen(flvFile, "rb+");
  SWFSoundStream sound(soundFD);

  // The original dimensions of the video are 426 X 240.
  di->rotate(-90);  // Rotate the item 90 degrees clockwise
  di->move(240, 0);  // The rotation moves point (0,240) to (-240,0).


  mov.setSoundStream(&sound,0);  // Add the sound stream at the beginning
                                 // of the movie.

  // Show the frames one by one.
  int noFrames = stream->getNumFrames();
  for (int i=0; i<noFrames; i++)
      mov.nextFrame();

  mov.setDimension(240, 426); // The new dimensions.
  mov.save("/path/to/outputVideoFile.swf", 9);
  cerr<<"Fin\n";
  return 0;
}

This will create a real vertical movie. Don’t share it on YouTube or anywhere you cannot control your movie dimensions.

Advertisements

Browsing From The Command Line / Server With cURL

cURL is a tool used for browsing the web from the shell or command-line. It supports many internet protocols, such as HTTP, FTM, POP3, IMAP, SMTP and more. See the full list here.

With libcurl installed in your system and the C API, you can browse using a C program. You can also install the extension cURL for PHP.

Steps of a cURL Program

  1. Obtain a curl handle
    For example:

    $curl_handle = curl_init();
  2. Set options to the handle.
    Define the behavior of curl when executing the request: setting the URL, cookie location, variables passed to the server, etc.
    In PHP, you can use curl_setop to set a single option, or curl_setopt_array to pass a PHP array.
    For example:

    curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,true);

    will cause cURL to store the output in a string; the value ‘false’ will cause cURL to send it to the standard output.

  3. Execute the request.
    $out=curl_exec($curl_handle);
  4. Close the handle
    curl_close($curl_handle);

As long as the handle is open, you can repeat steps 2 and 3 as many times as you need.

Another useful cURL function is curl_getinfo. In the example below, I have used

"$httpCode = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);"

to determine if the login action was successful.

 An Example – Sharing a Message in LinkedIn

Publishing a text message in LinkedIn is simple: surf to LinkedIn, find the relevant form in the response and submit it. I’ve found the login form and the publish form using HTML Dom documents. Then populated post vars according to them, and connected to the URL given in the “action” attribute of the form. The code is run in PHP CLI in Linux (“stty -echo” is a system call that suppresses the echoing of input characters in Linux).

Step I – Surf to LinkedIn

In this step cURL will send a request to get the content in linkedin.com This is the first time, so the user is not logged in, and there are no cookies. The option CURLOPT_USERAGENT will make the server believe that the request has been sent from a real browser. The option CURLOPT_COOKIEJAR will define the file from which to store and retrieve cookies.

Following is the code:

<?php
error_reporting(E_ERROR | E_PARSE); //Suppress warnings

$curl_handle = curl_init();

// Connect to the site for the first time.
curl_setopt($curl_handle,CURLOPT_URL,"https://www.linkedin.com");
curl_setopt($curl_handle,CURLOPT_USERAGENT,'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:35.0) Gecko/20100101 Firefox/35.0');
curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl_handle,CURLOPT_COOKIEJAR,'/tmp/cookies');
$out = curl_exec($curl_handle);
if (!$out){
  echo "Error: " . curl_error($curl_handle) . "\n";
  die();
}

Step II – Get the Login Form, Populate It, and Submit It

In this step your script will read your e-mail address and password from the standard input (“php://stdin”), then populate the login form, and submit it. Using the Firefox extension DOM Inspector, I found that the Id of the form element is ‘login’, the username (e-mail) field’s name is “session_key”, and the password field’s name is “session_password”. The script willl submit the form with the input fields of type ‘hidden’ and with the entered e-mail and password. If the login was successful, the http code returned in the header would be 302, which means the output is returned from another address.

Following is the code:

$stdin = fopen('php://stdin','r');
echo "Enter e-mail:";
$email = trim(fgets($stdin));
system("stty -echo");
echo "Enter Password:";
$pass = trim(fgets($stdin));
system("stty echo");
echo "\n";
// Get the form inputs.
$doc = new DOMDocument();
$doc->loadHTML($out);

$form = $doc->getElementById('login');
$inputElements = $form->getElementsByTagName('input');
$length = $inputElements->length;

$inputs = Array();
for ($i=0;$i<$length;$i++){
  $elem=$inputElements->item($i);
  $name = $elem->getAttribute('name');
  $value = $elem->getAttribute('value');
  $inputs[$name]=$value;
}
$inputs['session_key']=$email;
$inputs['session_password']=$pass;
$keys = array_keys($inputs);
$postvars = '';

$firstInput=true;
foreach ($keys as $key){
  if (!$firstInput)
    $postvars .= '&';
  $firstInput = false;
  $postvars .= $key . "=" . urlencode($inputs[$key]);
}
$submitUrl = $form->getAttribute('action');

curl_setopt_array($curl_handle, Array(
  CURLOPT_URL=>$submitUrl,
  CURLOPT_POST=>true,
  CURLOPT_POSTFIELDS=>$postvars
));
$out=curl_exec($curl_handle);
$httpCode = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);

if ($httpCode != 302)
  die("Error - could not connect: $httpCode\n");

Step III – Post the Silly Message

After a successful login, the relevant data is stored in the cookie jar associated with the cURL handle. This time the script will read the content of the home page with the user logged in. A logged-in user can post status updates. This time, the operation is not complete until the “browser” is referred to the new address. So, we set the cURL option “CURLOPT_FOLLOWLOCATION” to true. In addition, PHP cURL allows to send an associative array as the value of the option “CURLOPT_POSTFIELDS”, a more elegant way to send POST data.

Following is the code:

// Post the message
curl_setopt($curl_handle, CURLOPT_URL, 'https://www.linkedin.com');
$out = curl_exec($curl_handle);
$doc = new DOMDocument();
$doc->loadHTML($out);
$form=$doc->getElementById('share-form');
$inputElements = $form->getElementsByTagName('input');
$length = $inputElements->length;
$inputs=Array();
for ($i=0;$i<$length;$i++){
  $elem=$inputElements->item($i);
  $name = $elem->getAttribute('name');
  $value = $elem->getAttribute('value');
  $inputs[$name]=$value;
}
$inputs['postText']="Hello! I am a message sent by a PHP script.";
$inputs['postVisibility2']='EVERYONE';
$keys=array_keys($inputs);


$formAction = $form->getAttribute('action');
if (substr($formAction,0,5)!='http:')
  $formAction = 'http://www.linkedin.com' . $formAction;

curl_setopt_array($curl_handle, Array(
  CURLOPT_URL=>$formAction,
  CURLOPT_POST=>true,
  CURLOPT_FOLLOWLOCATION=>true,
  CURLOPT_POSTFIELDS=>$inputs
));
$out = curl_exec($curl_handle);

curl_close($curl_handle);
?>

Processing: Sketches – Your Multi-Programs

When you start Processing, you get an editor with a sketch name. You will probably want another name for your program, a name that means something. So, to change the name generated by the tool, you choose file->save as. Choose a name, and the tool will create a folder with that name, and a file named <name>.pde.

When you run your sketch – by clicking the button with the triange or selecting ‘sketch->Run …’ (Run In Browser, Run on Device, Run In Emulator, Run, etc. Depending on the mode) – Processing will parse the ‘.pde’ files and the program used for running will create an instance each time you run it.

Setup and Draw

If you want have things to do upon initiation of your program, define a function named ‘void setup()‘.  To size your canvas call size(width, height). It is recommended to use ‘size’ only once in the setup function, and the whole sketch. A setup command is not called in run time. It is recommended to set the frame rate inside the setup function by calling ‘frameRate(rate)‘, the rate is the number of time the function ‘draw()‘ is supposed to be call every second. If you want an action to take place each time a frame changes, write a “draw” function in one of  your ‘.pde’ files.

More Than Just Pure Processing

Sometimes, pure Processing is not enough for your application. For example, sound functions do not exist in pure Processing. There are libraries, such as Maxim,  that extend Processing.

Another reason to use more than pure Processing is will to use native widgets (HTML elements, Android Menus & Dialogs, etc.). In pure Processing, you would have to draw the button and detect in the ‘mouseClicked‘ function if the mouse pointer is inside the button.

Here’s a little video example of using the android menu to change the number of polygon sides:

In addition, I’ve created a Javascript module, and added buttons to the HTML page displayed when running in Javascript mode.

The following sections will explain how to do it.

 The Common Part: Just Draw a Polygon

The sommon part that draws the polygon is found in a ‘.pde’ file in the ‘polygon’ sketch directory. The function ‘draw’ detects changes in the global variable n, the number of sides.

The functions ‘translate’ and ‘rotate’ make drawing rotated shapes and lines easier.

In addition, the module contains a call to a function named ‘alert’. This function exists in Javascript, so I’ve made another in the Android module using Toasts.

Following is the code:

// This program draws a regular polygon with n sides.
int n;
float halfVertexAngle; // Will be used for moving from the center
                      // of the sreen to a vertex of the polygon.
                                          
float rotateAngle;     

void set_no_of_sides(int inputN){
  if (inputN < 3){
    alert("Polygons must have at least 3 sides. Try again");
    return;
  }
  n=inputN;
  halfVertexAngle = radians(180) / n; 
  rotateAngle = radians(360./n);
}

void setup(){
  //size(640,480);
  set_no_of_sides(8);
  background(0xffffff00);
  strokeWeight(1);
}

void draw(){
    background(0xffffff00);

  // Center coordinates of the screen and circumbscribed circle.

  int centerX = width / 2;
  int centerY = height / 2;
  
  
  float radius = min(width / 2, height/2);  // The radius of the circumscribed circle.
 
  // Use the cosine theorem to find the length of a side. 
  float side = sqrt(2 * radius * radius * (1 - cos(2 * halfVertexAngle)));
  
  translate(centerX, centerY);  // Move the origin of axes to the center of the screen.
  rotate (-halfVertexAngle);    // Rotate the axes to find the first vertex without
                                // dealing with trigonometry.
  translate(0, radius);
  rotate(halfVertexAngle);      // Rotate back to make the first side horizontal.
  
  for (int i=0; i<n; i ++){
    line(0,0,-side,0);
    translate(-side,0);
    rotate(rotateAngle);
  }
}

The Android Module

I found that in my Linux system Android files are created in the ‘/tmp’ directory. Processing Android mode generates an extension of the class PApplet from your pde files. The good news is that PApplet extends the android Activity class, which makes adding event handlers easy.

Additional functions to a class extending PApplet should be written in a separate pde file. Following is the extension’s code:

import android.os.Bundle;
import android.widget.Toast;
import android.view.Menu;
import android.view.MenuItem;
import android.app.AlertDialog;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.content.DialogInterface;

AlertDialog.Builder alertDialog=null;

public void alert(String text){
  Toast toast=Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG);
  toast.show();
}

public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  
}

 public boolean onCreateOptionsMenu (Menu menu){
   super.onCreateOptionsMenu (menu);
   menu.add(Menu.NONE, 37, Menu.NONE, "Change Number of sides");
   return true;
 }
 
 private void createAlertDialog(){
     // Create a dialog to change the number of polygon sides.
  alertDialog = new AlertDialog.Builder(this);
  alertDialog.setTitle("Polygon Settings");
  alertDialog.setMessage("Enter number of polygon sides:");
  final EditText input = new EditText(polygon.this);
  LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                                    LinearLayout.LayoutParams.MATCH_PARENT,
                                    LinearLayout.LayoutParams.MATCH_PARENT);
  input.setLayoutParams(lp);
  alertDialog.setView(input);
  alertDialog.setPositiveButton("Accept",
    new DialogInterface.OnClickListener(){
      public void onClick(DialogInterface dialog, int which){
        int numberParsed;
        try {
          numberParsed = Integer.parseInt(input.getText().toString());
          set_no_of_sides(numberParsed);
        } catch (NumberFormatException ex){
          alert("Not an integer. Try again.");
        }
      }
    });

  alertDialog.setNegativeButton("Cancel",
    new DialogInterface.OnClickListener(){
      public void onClick(DialogInterface dialog, int which){
      }
    });

 }
 
 public boolean onMenuItemSelected(int featureId, MenuItem menuitem){
   super.onMenuItemSelected(featureId, menuitem);
   switch (menuitem.getItemId()){
     case 37:
       createAlertDialog();
       alertDialog.show();
       break;
     default:
       break;
   }
   return true;
 }

Notes:

  • If you have an Android module, but you want to run in another mode, renaming the Android mode’s pde file with a ‘.bak’ extension is recommended.
  • If the Android module is not installed, you can install it from a Processing editor window, by selecting <mode button> -> Add more…

Javascript Functions & Changes to the HTML Page

You can change the appearance of your output HTML page by editing the file <sketch-name>/template/template.html . If the file and directory do not exist yet, you can create them by choosing “Javascript->Start Custom Template”. If they do exist use “Javascript-.Show Custom Template”.

For example, I’ve added a button in the HTML template as follows:

<input type="button" value="Change Number of Sides" onclick="get_no_of_sides(this);" />

In addition, I’ve added an ‘onload’ event to change the size of the canvas after the polygon object is created. This function works fine in my favorite browser, Firefox. Fortunately, from ‘.js’ module one can call ‘size’ to resize the canvas:

    <body onload="new_size(640, 480);">

From this page you can learn about accessing Processing from Javascript.

Following is my javascript code defined in ‘js_functions.js’:

function new_size(w, h){
  var divElement=document.getElementById('content');
  divElement.addEventListener("DOMSubtreeModified", function(event, func){
    if (window.Processing.getInstanceById("polygon")){
      divElement.removeEventListener("DOMSubtreeModified", arguments.callee);
      divElement.style.width = w + "px";
      window.Processing.getInstanceById("polygon").size(w,h);
    }
  });

function get_no_of_sides(obj){

  var k=prompt("How many sides?");
  var num=Number(k);
  if (isNaN(num) || num != parseInt(k)){
    alert("Please type an integer");
    return;
  }

  this.Processing.getInstanceById('polygon').set_no_of_sides(num);
}

Now, when you run your application, the product will be found in ‘<sketch-name>/web-export’.
Learn more about Javascript modules here.

Creating Flash Sites With Ming

You probably know the SWF file format. This is not just a movie, but also can be an interactive application. SWF files can be created with the Ming PHP extension. You can get information on how to install and use the extension here. The movie format can be extended with a special scripting language, named ActionScript. Ming is not well-documented, so you can download a little API here, and maybe it will help you. There are also class for creating GUI objects, such as buttons, text fields, etc.

Let’s Discuss Some Classes

SWFMovie -The main class for movies, used for creating movies, and writing them to output streams.

Useful functions:

  • The constructor of course.
  • add – to add various objects, such as SWFAction scripts, sprites, shapes, buttons, text, etc.
  • save – to save your work to a file.
  • output – to send the output to the browser. before you send it, define the MIME type using
    header(‘Content-type: application/x-shockwave-flash’);

Notes:

  • Define the SWF version before you play it, or you will not be able to view the clip. Here‘s an user-contributed example of a way to determine the version and find more useful details. Set the version with ‘ming_useswfversion’.
  • Use scaling to avoid movies in strange sites at strange screen locations. We’ll discuss it later.
  • If you have created a movies from another movie, you must have access to the original movie from the new movie.

SWFAction – a class used for creating scripts. The scripts ca add functionality to the movie and make it interactive. It’s only function is the constructor, that takes scripts as its argument. You can use it for adding text fields – including input text fields -, communicate with other sites (using the LoadVars class for example), jumping to other frames, defining events, etc. Add it to your movie clips with the function ‘add’. Read more here.

an example of scaling with this class is:

  Stage.scaleMode='noScale';

Note: Error messages are not sent to the log, if they are not syntax errors.

SWFShape – used for creating shapes. This can be used for defining the shape of buttons (need not be rectangular). It can also be added to movie clips. With this class you can draw lines, arcs, and quadratic and cubic Bezzier curves.  You can fill your shape with colors, gradients or bitmaps. If your fill is an image, you can create an object of class SWFFill using “addFill ( SWFBitmap $bitmap [, int $flags ] ).”.  Then you can fill your shape using ‘setRightFill’ or ‘setLeftFill passing your fill as the argument.

SWFFill – This class does not have a constructor. An instance of this class is created by the function addFill of class  SWFShape . It is important to move the fill to the exact location using the function ‘moveTo’ and to scale it using ‘scaleTo”. If you want to use an image at its original dimension, you will probably have to scale it to (20,20) $fill->scaleTo(20,20) because the number of horizontal and vertical twips in a pixel is 20. In addition the fill can be rotated and/or skewed.

SWFButton – A button is a GUI element that triggers an action when clicked. You can add actions, sounds and shapes using the function addAction/setAction, addSound and addShape respectively. You better add a shape, to define the shape and location of the button. The prototype of addShape is ‘void addShape ( SWFShape $shape , int $flags )’. The flags are a combination (using bitwise or) of SWFBUTTON_UP, SWFBUTTON_OVER, SWFBUTTON_DOWN and SWFBUTTON_HIT. These flags define when the button is displayed.

An Example

This is an example of a script that plays a movie backwards:

$x = new SWFMovie();
.
.
.

$actionText = <<<'EOT'

this.createEmptyMovieClip("mc",2);

mc.loadMovie("selfie.swf", "GET");
this.gotoAndStop(mc._totalframes - 1);
this.createTextField("myText", this.getNextHighestDepth(), 0, 0, 200,220);
var tf:TextFormat = new TextFormat();
tf.color = 0x0;
tf.size = 30;
tf.font = "Arial";
myText.setTextFormat(tf);
this.addChild(myText);

this.onEnterFrame=function(){
  if (mc._currentFrame <= 1){
    mc.gotoAndPlay(mc._totalframes - 1);
  }
  mc.prevFrame();
}; 

EOT;
$act=new SWFAction($actionText);
//$x->add($text);
$x->add($act);


How To Develop Firefox Extensions – Files And Directories (Actually Coding It)

In the previous post, How To Develop Firefox Extensions – Intro, we discussed the Chrome document’s DOM. In this post, we’ll learn how to create an add-on that can be installed.  In this post, we’ll learn how to access the Chrome document’s nodes, and to organize an XPI (Cross Platform Installer) file.

XPI files are ZIP files

A file having an ‘.xpi’ suffix, is a compressed file in ‘.zip’ format. If we use Firefox as the opening program for those files, it will install an extension. We can refer to a zipped file as a root directory, containing files and sub-directories.

Following is a recommended directory structure:

  • /
    • install.rdf
    • chrome.manifest
    • content/
      • <filename>.xul
      • <filename>.js
    • locale/
      • <language code>/
        • <filename>.dtd
      • <language code>/
        • <filename>.dtd
      • .
      • .
      • .
    • skin/
      • <filename>.css

The XUL File

The XUL file is located in the content directory. XUL is an acronym for *XML User-interface Language’. The XUL file is a data file that makes the development of Mozilla extensions easier. The following example is an Overlay XUL file, i.e. an XUL used for adding a component to the browser’s Chrome, the great UI container.

<?xml version="1.0"?>
<!DOCTYPE overlay SYSTEM
  "chrome://imageinnewtab_extension/locale/browserOverlay.dtd">

<overlay id="imageinnewtabextensionOverlay"
         xmlns:html="http://www.w3.org/1999/xhtml"
         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

 <script src="imageinnewtab_extension.js">
 </script>

    <menupopup id="contentAreaContextMenu"  >
        <menuitem id="context-imageinnewtab"
                  label="&phpandmoreimageinnewtab.image-new-tab.label;"
                  oncommand="ImageInNewTab.BrowserOverlay.openInNewTab(event)"
                  insertafter="context-viewimage"
                  hidden="true"
                 />
    </menupopup>

</overlay>

This overlay contains the required data for adding an “Open Image In New Tab” option to the context-menu that pops up when you right-click in the HTML document area. This file contains a link to a script and instructions to add a new menu item to the popup menu with the unique id ‘contentAreaContextMenu’.

Note that the value of the label attributes begins with an ampersand(‘&’) and ends with a seni-colons; this means that the value is variable. The actual value is translated according to the definitions found in the DTD file specified in the ‘!DOCTYPE’ tag.

The ‘oncommand’ attribute defines how Firefox should response to command events, i.e. the function called when the menu item is selected either by a mouse click or by a keyboard shortcut.

Learn more about XUL here.

The Javascript file

In this example, ‘content/imageinnewtab_extension.js’, the Javascript file, defines an object that response to the ‘command’ event. The object is initialized as a response to the “load” event, i.e. after the UI components has completed loading. When the Chrome document has completed loading, the new menu item is defined. The ‘init’ member is a function that defines what callback function to call when the context menu pops up.

Following is the code:

if ("undefined" == typeof(ImageInNewTab)) {
  var ImageInNewTab = {};
};

ImageInNewTab.BrowserOverlay = {
    hideIfNoImage: function(event){
      var element=document.popupNode;
      var whatWasClicked = document.getElementById("context-imageinnewtab");
      whatWasClicked.hidden = !(element instanceof Components.interfaces.nsIImageLoadingContent &&
                 element.currentURI);
    },

    init: function (event){
        var contextMenu = document.getElementById("contentAreaContextMenu");
        contextMenu.addEventListener("popupshowing", ImageInNewTab.BrowserOverlay.hideIfNoImage, false);
    },

    openInNewTab: function (event){
      gBrowser.addTab(document.popupNode.src);
    }

}

addEventListener("load",
                 ImageInNewTab.BrowserOverlay.init,false);

The Install RDF file

The ‘install.rdf’ file includes information for the browser. The information includes information shown to the installing end-uder, and for the browser to know if the extension supports the current browser version.

Following is an example:

<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
    <Description about="urn:mozilla:install-manifest">
        <em:id>imageinnewtab_extension@phpandmore.net</em:id>
        <em:name>Image in New Tab</em:name>
        <em:version>0.1</em:version>
        <em:description>Add a new Menu Item in the context menu to view an image in a new tab.</em:description>
        <em:creator>Amit Yaron</em:creator>
        <em:homepageURL>https://phpandmore.net/</em:homepageURL>
        <em:type>2</em:type> <!-- type=extension --> 

        <em:targetApplication>
           <!-- Firefox -->
           <Description>
                <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
                <em:minVersion>3.5</em:minVersion>
                <!-- Since Firefox's numbering scheme is unpredictable, users
                are encouraged to edit this field to the current max value.
                -->
                <em:maxVersion>999.0.*</em:maxVersion>
           </Description>
        </em:targetApplication>
    </Description>
</RDF>

Note: don’t change the ’em:id’ tag value.

Learn more about the install.rdf here.

The Chrome Manifest

The ‘chrrome.manifest’ file is a simple text files that contains instructions on how to access Chrome URL addresses (beginning with ‘chrome://’.

Following is an example manifest:

content imageinnewtab_extension content/
skin imageinnewtab_extension classic/1.0 skin/
locale imageinnewtab_extension en-US locale/en-US/
locale imageinnewtab_extension he-IL locale/he-IL/

overlay chrome://browser/content/browser.xul chrome://imageinnewtab_extension/content/imageinnewtab_extension_overlay.xul
  • The ‘content ‘ instruction tells Firefox where to find ‘chrome://imageinnewtab_extension/content’, where the XUL and code are found.
  • The ‘skin ‘ instruction tells Firefox where to find ‘chrome://imageinnewtab_extension/skin’, where the CSS files are found.
  • The ‘locale ‘ instruction tells Firefox where to find ‘chrome://imageinnewtab_extension/locale’ according to the ‘LANG’ environment variable, This is where the DTD file, used for label translation, is found.
  • The ‘overlay’ instruction tells Firefox the role of the overlay XUL file, which extends the great UI container.

Learn more about the manifest here.

The Example Add-on

The example add-on, that opens an image in a new tab, can be downloaded here.

How To Develop a Firefox Extension – Intro

Firefox users can add functionality to their browser by installing an add-on.  To install an add-n click on Tools->Add-ons.

Add On

You can then search for your requested add-on: add-on to download movies from a site, to share a page in Facebook, to add a Delicious bookmark, etc. Another useful add-on is DOM Inspector, which allows you to locate and modify document elements. Firefox add-ons are written in Javascript and access document elements, just like Javascript scripts within HTML documents, except that the document an add-on accesses is named Chrome Document.

Accessing the Chrome Document

The Chrome document contains more than just the “window” element, accessed from a web page using Javascript. Chrome also contains menus, toolbars and other widgets. Let’s make changing one of the Chrome document’s elements your first step in add-on development. If you don’t have DOM Inspector installed in your browser, you can get it here. Now, you can use it to play around a little bit. For example, let’s change the ‘Tools’ menu’s name to ‘Fools’.

To do so, perform the following steps:

  1. Tools->Web Developer->DOM Inspector:
    StartDomInspector
  2. In the DOM Inspector menu bar, choose: File->Inspect Chrome Document->(tab name)
    InspectChromeDocument
  3. In the DOM Inspector Window, click the magnifying-glass icon.
    MagnifyingGlass
  4. In the browser’s window click ‘Tools’ menu
    IMPORTANT! This will NOT work if the “Global Menu BAR Integration” add-on is enabled!!!
  5. Open the DOM Inspector window.
    The ‘tools-menu’ node will appear on the right-hand part of the window.
    tools-menu
    Now, you can see that the value of the node’s “label” attribute is “Tools”
  6. Right click the “Label” attribute, then left-click “Edit”.
    clickEdit
  7. In the “Edit Attributes” window opened change the Node Value and click “OK”.
    editAttributes
  8. Nice work!!!
    niceWork

Congratulations! Now you know how to access chrome elements and modify them. This will help you later when you learn how to do it in Javascript.

Learn more about add-on development here.

Extending PHP

Extending PHP does not mean just adding classes and functions. It also means adding functionality not previously supported by PHP. This can be done by writing functions in C that can be called from PHP. These functions should be able to receive parameters passed from PHP. The difference between a variable in a C source and a variable in PHP is that in PHP the variable in PHP is loosely typed. That is, in PHP a variable can be used as an integer, but later as a string or a floating point number, so its equivalent in C is zVal. “zval” is a structure containing the variable’s type and a union made up of members of different types sharing the same memory address.

The PHP extension is a dynamically linked library (‘dll’ in Windows, ‘so’ in Linux) containing functions that can be called from PHP.

The process of creating an extension is described in the chapter “PHP at the Core: A Hacker’s Guide to the Zend Engine” in the famous PHP manual.

Building the extension starts with tunning the ‘ext_skel’ script, which creates a directory for your extension including a skeleton of the extension’s C code and a header file.

The next step is to add functions and global variables using macros.

The macro used for defining a  function is PHP_FUNCTION(function_name). Returning a value is done using the macros RETURN_TRUE, RETURN_FALSE, RETVAL_* . These macros are in /path/to/php_include_dir/Zend/zend_API.h

Arguments are passed to local C variables using the function ‘zend_parse_parameters’.

The next step is to edit config.w4(Linux) or config.w32(windows), then run ‘phpize’ and ‘configure’ to create a Makefile.

Finally, run make.

The dynamically loaded library will be created in the ‘modules’ directory. Use ‘make install’ with root permissions to copy your extension to the PHP extension directory.

Unfortunately, the guide is far from being complete, so to look for examples, browse ‘pecl.php.net‘ for source codes.