Finding magic.mgk in a deployed Mac app

After a lot of frustration I decided that the best way to have GraphicsMagick/ImageMagick finding the required magic.mgk file inside YourApp.app/Contents/Resources is to patch the image library code.

The change is quite trivial and I’ve pasted the diff below. This patch was applied to GraphicsMagick version 1.3.7. Basically it uses the path provided via magick::InitializeMagick(“executable/path”) to find Contents/Resources. Have fun!!!

diff -r 152043af6bf4 magick/blob.c
--- a/magick/blob.c	Wed Nov 18 00:05:49 2009 +0000
+++ b/magick/blob.c	Wed Nov 18 00:29:25 2009 +0000
@@ -1741,6 +1741,18 @@
 #endif /* !defined(UseInstalledMagick) */
 
 
+
+  {
+		// ruibm added
+		
+		char buffer[2048];
+		sprintf(buffer, "%s/../Resources/", GetClientPath());
+		// printf("Adding [%s] to the search path.n", buffer);
+		AddConfigurePath(path_map,&path_index,buffer,exception);
+  }
+
+
+
   path_map_iterator=MagickMapAllocateIterator(path_map);
 
   if (logging)

Mac Application Deployment – dylib

Lately I’ve been battling away with the Mach-O binary file format. I am trying to create a Mac version of an application that depends on dylibs provided by wxWidgets and GraphicsMagick. I started this quest by finding out the hard way that mac binaries (libs and applications) store the path to their dylib dependencies in the binary itself. As you can imagine this is a big hassle for app deployment as you force every user wanting to install the app to have the same exact /usr/lib and /opt/local/lib as your machines does.

After a bit of scavenging in forums I found out that otool allows you to print the list of dependencies of a binary and that install_name_tool allows you to change them. Bearing this in mind I now wanted the simplest way I could get to change the list of dependencies both in my binary and inside all of its dependency dylibs. I ended up writing the python script below for this.

#!/usr/bin/python
# 
# Uses otool and install_name_tool to change a given path in the list of 
# dylib dependencies to another (hopefully relative) path to ease deployment.
# If this is applied to dylib files it will also change their ID.
#
# Author: Rui Barbosa Martins (ruibm@ruibm.com)

import os.path
import re
import subprocess
import sys

def RunCmd(cmd):
	obj = subprocess.Popen(cmd, shell=True, bufsize=42000, stdout=subprocess.PIPE)
	out = ""
	while (True) :
		content = obj.stdout.read()
		if content:
			out += content
		else:
			break
	ret_code = obj.wait()
	if ret_code == 0:
		return out
	else:
		return None
	
	
def GetDependencies(file):
	cmd = "otool -L " + file
	output = RunCmd(cmd)
	if not output:
		raise Exception("Problem running otool. [%s]" % (cmd))
	output = output.split("n")
	deps = list()
	for line in output:
		m = re.match("(.*)\(compatibility version.*", line);		
		if not m:
			continue
		dylib = m.group(1).strip()
		deps.append(dylib)
	return deps

	
def ChangeDependecies(file, dependencies, replaceFrom, replaceTo):
	print "Changing dependencies in %s" % (file)
	fname = os.path.basename(file)
	for d in dependencies:
		if not replaceFrom in d:
			continue
		
		new = d.replace(replaceFrom, replaceTo)
		if fname == os.path.basename(d):
			cmd = "install_name_tool -id %s %s" % (new, file)
			print "ID: %s -> %s" % (d, new)
		else:			
			cmd = "install_name_tool -change %s %s %s" % (d, new, file)
			print "Change: %s -> %s" % (d, new)
		RunCmd(cmd)
		

def main(argv) :
	if len(argv) != 4:
		print "Usage: %s [file] [replaceFrom] [replaceTo]" % (argv[0])
	file = argv[1]
	replaceFrom = argv[2]
	replaceTo = argv[3]
	deps = GetDependencies(file)
	ChangeDependecies(file, deps, replaceFrom, replaceTo)

if __name__ == "__main__":
	main(sys.argv)
	

OpenGL ES 1.0 on Android – Triangle Example

Android LogoSince I spent quite a few hours trying to get my first OpenGL ES triangle on the Android phone’s screen I thought I should share the code with everyone to ease a bit the pain. Hopefully this will help someone get going on Android.


MainActivity.java

package com.ruibm;

import android.app.Activity;
import android.graphics.PointF;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;

public class MainActivity extends Activity {

  private PointF touchStart;
  private GLSurfaceView glSurfaceView;
  private TriangleRenderer renderer;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    touchStart = new PointF();
    glSurfaceView = new GLSurfaceView(this);
    renderer = new TriangleRenderer();
    glSurfaceView.setRenderer(renderer);
    setContentView(glSurfaceView);
  }

  @Override
  protected void onResume() {
    super.onResume();
    glSurfaceView.onResume();
  }

  @Override
  protected void onPause() {
    super.onPause();
    glSurfaceView.onPause();
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
      case MotionEvent.ACTION_MOVE:
        renderer.move(event.getX() - touchStart.x, touchStart.y - event.getY());
        touchStart.set(event.getX(), event.getY());
        glSurfaceView.requestRender();
        return true;

      case MotionEvent.ACTION_DOWN:
        touchStart.set(event.getX(), event.getY());
        return true;

      default:
        return super.onTouchEvent(event);
    }
  }

  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    switch (keyCode) {
      case KeyEvent.KEYCODE_DPAD_UP:
        renderer.move(0, 1);
        glSurfaceView.requestRender();
        return true;

      case KeyEvent.KEYCODE_DPAD_DOWN:
        renderer.move(0, -1);
        glSurfaceView.requestRender();
        return true;

      case KeyEvent.KEYCODE_DPAD_LEFT:
        renderer.move(-1, 0);
        glSurfaceView.requestRender();
        return true;

      case KeyEvent.KEYCODE_DPAD_RIGHT:
        renderer.move(1, 0);
        glSurfaceView.requestRender();
        return true;

      default:
        return super.onKeyDown(keyCode, event);
    }
  }
}

TriangleRenderer.java

package com.ruibm;

import java.nio.ShortBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.graphics.PointF;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;

public class TriangleRenderer implements Renderer {
  
  private PointF surfaceSize;
  private PointF offset;
  private ShortBuffer triangleBuffer;
  
  public TriangleRenderer() {
    surfaceSize = new PointF();
    offset = new PointF();
  }

  public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  }
  
  public void onSurfaceChanged(GL10 gl, int width, int height) {
    surfaceSize.set(width, height);

    // Create our triangle.
    final int div = 1;
    short[] triangles = { 
        0, 0, 0,
        0, (short) (surfaceSize.y / div), 0,
        (short) (surfaceSize.x / div), (short) (surfaceSize.y / div), 0,
    };    
    triangleBuffer = ShortBuffer.wrap(triangles);
    
    // Disable a few things we are not going to use.
    gl.glDisable(GL10.GL_LIGHTING);
    gl.glDisable(GL10.GL_CULL_FACE);
    gl.glDisable(GL10.GL_DEPTH_BUFFER_BIT);
    gl.glDisable(GL10.GL_DEPTH_TEST);
    gl.glClearColor(.5f, .5f, .8f, 1.f);
    gl.glShadeModel(GL10.GL_SMOOTH);
    
    float ratio = surfaceSize.x / surfaceSize.y;
    gl.glViewport(0, 0, (int) surfaceSize.x, (int) surfaceSize.y);
            
    // Set our field of view.
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();
    gl.glFrustumf(
        -surfaceSize.x / 2, surfaceSize.x / 2, 
        -surfaceSize.y / 2, surfaceSize.y / 2,
        1, 3);
    
    // Position the camera at (0, 0, -2) looking down the -z axis.
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    // Points rendered to z=0 will be exactly at the frustum's 
    // (farZ - nearZ) / 2 so the actual dimension of the triangle should be
    // half
    gl.glTranslatef(0, 0, -2);
  }

  public void onDrawFrame(GL10 gl) {    
    gl.glPushMatrix();
    
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    gl.glTranslatef(offset.x, offset.y, 0);
    
    gl.glColor4f(1.0f, 0.3f, 0.0f, .5f);    
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glVertexPointer(3, GL10.GL_SHORT, 0, triangleBuffer);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);    
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    
    gl.glPopMatrix();
  }

  public void move(float xDelta, float yDelta) {
    offset.x += xDelta;
    offset.y += yDelta;
    Log.d("TriangleRenderer", "offset=[" + offset.x + " ," + offset.y + "]");
  }
}

Windows Vista Activation

Windows Vista UltimateMicrosoft’s effort to force customers to pirate their software never ceases to astonish me. I have lately been trying Parallels versus VMWare Fusion on my Mac with my purchased version of Windows Vista Ultimate. I know some people will point out that I’d be better off by burning it down altogether but I have nothing against Windows users and I’d like to be able to compile my applications for their system.

That being said, it seems that using Parallels and VMware Fusion causes the platform detection system quite a headache. It has by now decided that I have Windows installed in several machines therefore I’m not entitled to use it anymore… I must say that at this point it’s a similar effort to go through Microsoft telephone service or just get a cracked key. Being in a good mood and all I decided I’d give Microsoft dudes a chance and made the phone call.

First thing I need to point out is that if you thought having to manually copy the serial key to the Windows installation dialog was hard enough, then you haven’t seen anything. Microsoft telephone activation service presents itself as a total of 48 digits you need to dial in to the phone just to get back another bundle of freshly baked 48 digits. If my math does not betray me this is a total of 96 digits that Microsoft expects you to copy flawlessly in order to prove yourself worthy of running a fully activated Windows Vista system. After spending 15min on the phone I believe that even my girlfriend started getting jealous of this woman voice that seemed to be bonding so well with me with so many numbers being dictated back and forth.

Eitherway, I’m quite glad to say that it all worked and I have now a VMware Fusion Windows Vista image that is actually activated. I’m now not so impressed with the 30GB it seems to already be taking even though I installed the smallest Windows footprint possible with Visual Studio. I guess I’ll leave this rant for another post. Taaa!

AppleScripts for Finder

I found recently this amazing Mac application called Spark that allows you to define global shortcuts keys (hotkeys). Here are some utility scripts I conjured to make my life easier.

Copy the current Finder path to the clipboard.

tell application "Finder"
	set theWindow to window 1
	set thePath to (POSIX path of (target of theWindow as alias))
	set the clipboard to thePath
end tell

Open an iTerm in the current Finder location.

tell application "Finder"
	if ((count the window) < 1) then
		return
	end if
	set theWindow to window 1
	set thePath to (POSIX path of (target of theWindow as alias))
	my openTerminal(thePath)
end tell

on openTerminal(path)
	tell application "iTerm"
		activate
		if not (exists current terminal) then
			launch session "Default Session"
		end if
		set mysession to current session of current terminal
		select mysession
		set cmd to "pushd " & path
		write mysession text cmd
	end tell
end openTerminal

Quick python socket server that stdouts all input

And here’s a simple python script that allows you to connect to your machine and debug your client output. It basically echoes to stdout everything that gets passed to it. Specially useful to debug HTTP GET requests.

#!/usr/bin/env python
#  Disconnect the client.
#  Stop the server.

import socket
import sys

host = ''
# host = 'localhost' # to restrict to localhost connections only.
port = 3434
pending_connections = 1
buffer_size = 1

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(pending_connections)
try:
  while True:
      print "nnWaiting for connection..."
      client, address = s.accept()
      print "Client connected: " + str(address)
      while True:
        data = client.recv(buffer_size)
        if not data or chr(3) in data:
          break
        elif chr(24) in data:
          sys.exit(0)
        sys.stdout.write(data)
      client.close()
      print "nClient disconnected: " + str(address)
finally:
  s.close()

Rounded corner bitmaps on Android

In Android, you can create bitmaps with anti-aliased rounded corners on the fly using the code snippet below. If anyone finds a more obvious way please feel free to ping me – I’d really love to know about it.

(This code may be used under the terms of Apache License – Version 2)

  public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
        bitmap.getHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    final int color = 0xff424242;
    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
    final RectF rectF = new RectF(rect);
    final float roundPx = 12;

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(bitmap, rect, rect, paint);

    return output;
  }

2 + 2 = 5

This weekend I had the pleasure of reading 1984 written by George Orwell. I really can’t think of any adjective that qualifies this book in all its greatness. Really loved the way O’Brien asserts that controlling one’s mind is controlling the reality – there is no other reality other than the one the man’s conscious mind is able to perceive and controlling that is controlling the laws of the Universe. Basically if one can push any thing to the human’s mind that they’ll accept as real, then as far as everyone’s concerned it is actually real. Brilliant book – strongly recommend everyone to read it.

Another book that I’ve finished recently and also recommend is Douglas Adams’ “Last Chance to See…”. It’s a lightweight reading where Douglas narrates his journey around the globe to find species on the brink of extinction. The weird situations he ended up in along with his unique sense of humor make this a very enjoyable book to go through!