Warning: mysql_connect(): Access denied for user 'mysql_feedback'@'localhost' (using password: YES) in /usr/local/psa/home/vhosts/coin-c.com/httpdocs/CCTunes/inc_rate.php on line 18
I cannot connect to the database because: Access denied for user 'mysql_feedback'@'localhost' (using password: YES)

6. Getting the images out of the mp3 files

The trickiest part of the job was getting the images. Since the images are not in the XML file we need to get them out of the mp3 files themselves. iTunes uses the correct mp3 v2 tag to store the image. Now, initially I wrote a perl script to extract the images based on a perl module. But, you need to install the perl modules MP3::Info and URI::URL in order for this to work. This is not too hard to do, but is still some effort. I could have packaged the perl modules I guess, but I found it easier to create a little Cocoa command line tool that does the same based on libid3, the library that is distributed by http://www.id3.org. Both approaches are still explained however.

Using a custom command line tool to get the image out of the mp3 file

Another approach is taken in the downloadable package however. The getPicure command is not a perl command, but a compiled tool, based on id3v2 which already uses the libid3 library and has a great set of functionalities, except... extracting images.

Adapting the sources to eliminate all we don't need and adding the extra little bit of functionality to extract the image was easy however, since we basically know how to do this in perl already. In order to compile it you will need to have the libid3 headers in place and have a libid3 library that you can link to. The commands needed to compile it with the statically linked library are included in comments in the source code.

Code listing 6.1: Source code to getPicture command line tool

/**
 * Based on id3v2 ... compile something like
 *
 * g++ -I/usr/local/include/ -O3   -c -o getpic.o getpic.cpp
 * c++ -L/usr/local/lib/ -O3 -pedantic -Wall -framework CoreFoundation -lz -liconv
 *                       -g -o id3v2 getpic.o ./libid3.a
 * 
 * Part of CCTunes, distributed under the GPL.
 * details at http://www.coin-c.com/CCTunes/
 */

#include <CoreFoundation/CoreFoundation.h>

#include <id3/misc_support.h>
#include <id3/tag.h>

#include "frametable.h"
#include "genre.h"

int main( int argc, char *argv[]);
int main( int argc, char *argv[])
{
  bool tags = false;
  CFURLRef theSourceUrl = CFURLCreateWithBytes(kCFAllocatorDefault,
					       (unsigned char*)argv[1],
					       strlen(argv[1]),
					       kCFStringEncodingUTF8,
					       NULL);
  unsigned char sourceFilePath[500];
  if (CFURLGetFileSystemRepresentation(theSourceUrl,true,sourceFilePath,500))
    {

      ID3_Tag myTag;
      myTag.Link((char*)sourceFilePath, ID3TT_ID3V2);

      const ID3_Frame * myFrame = 0;
      const ID3_Tag myTagConstRef = myTag;
      ID3_Tag::ConstIterator *Iter = myTagConstRef.CreateIterator();
      for (size_t nFrames = 0; nFrames < myTag.NumFrames(); nFrames++)
	{
	  myFrame = Iter->GetNext();
	  if (NULL != myFrame && myFrame->GetID() == ID3FID_PICTURE)
	    {
	      myFrame->Field(ID3FN_DATA).ToFile(argv[2]);
	      tags = true;
	      break;
	    }
	}
    }
    if(!tags)
      std::cout << "<warning><id>no_picture</id><info>" << (unsigned char*)argv[1]
                << "</info></warning>" << std::endl;
}


Generating Thumbnails

This might be all you need if you are on your own private server, have lots of disk space and don't really care on how fast your collection loads in the browser. Since I have been using this, I found that the size of the images tends to be too big to view all of the images for all of the albums at once, so it would be nice to generate thumbnails for the overview.

However, for your ease of use, the currently downloadable package comes with a little command line tool programmed in cocoa and based on pdf2png by Evan Jones which does all of this for you. It simply takes an image and draws it in an offline buffer of the specified size and saves that as a png file. I must say however, you will see that the quality is not good. It is the same quality you can see if you use iPhoto to look at the images you've taken with your digital camera. Uuuugly. I must provide some feedback to Apple on that someday.

Code listing 6.2: Little Cocoa command line tool to resize images, based on pdf2png

// A tiny program that resizes images to PNG images with certain dimensions.
// based on pdf2png by Evan Jones, http://evanjones.ca/pdf2png.m
// modified by Kristof Van Landschoot, Coin-C to fit the purpose of resizing.
//
// gcc --std=c99 -g -o resize resize.m -framework Cocoa
//
// Written originally by Evan Jones <ejones@uwaterloo.ca> Februrary, 2004
// http://www.eng.uwaterloo.ca/~ejones/
//
// Released under the GNU Public License

#include <Cocoa/Cocoa.h>

int main( int argc, char* argv[] )
{
	int destinationSize = 36; // in DPI

	int page = 1;
	
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	
	// Package all arguments as NSStrings in an NSArray
	NSMutableArray* args = [NSMutableArray arrayWithCapacity: argc - 1];
	for ( int i = 1; i < argc; ++ i )
	{
		[args addObject: [NSString stringWithCString: argv[i]] ];
	}
	
	// If we have a "--dpi" along with a corresponding argument ...
	unsigned int index = NSNotFound;
	if ( (index = [args indexOfObject: @"--dpi"]) != NSNotFound && index + 1 < [args count] )
	{
		// Parse it as an integer
		destinationSize = [[args objectAtIndex: index + 1] intValue];
		[args removeObjectAtIndex: index + 1];
		[args removeObjectAtIndex: index];
	}
	
	if ( [args count] != 2 || [args indexOfObject: @"--help"] != NSNotFound || destinationSize <= 0 )
	{
		fprintf( stderr, "resizePicture [options] file\n" );
		fprintf( stderr, "\t--dpi dpi\tSpecifies the destination size of the image in pixels\n" );
		fprintf( stderr, "\t--help\tPrint this help message\n" );
		return 1;
	}
	
	NSString* sourcePath = [args objectAtIndex: 0];
	NSImage* source = [ [NSImage alloc] initWithContentsOfFile: sourcePath ];
	[source setScalesWhenResized: YES];
	
	// Tip from http://www.omnigroup.com/mailman/archive/macosx-dev/2002-February/023366.html
	// Allows setCurrentPage to do anything
	[source setDataRetained: YES];
	
	if ( source == nil )
	{
		fprintf( stderr, "Source image '%s' could not be loaded\n", argv[1] );
		return 2;
	}
	
	// The output file name
	NSString* outputFilePath = [args objectAtIndex: 1];
	
	NSSize sourceSize = [source size];
		
	NSSize size = NSMakeSize( destinationSize, destinationSize );
	
	[NSApplication sharedApplication];
	[[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh];
	
	[source setSize: size];
	NSRect destinationRect = NSMakeRect( 0, 0, size.width, size.height );
	
	NSImage* image = [[NSImage alloc] initWithSize:size];
	[image lockFocus];
	    
	NSEraseRect( destinationRect );
	[source drawInRect: destinationRect
		fromRect: destinationRect
		operation: NSCompositeCopy fraction: 1.0];
	
	NSBitmapImageRep* bitmap = [ [NSBitmapImageRep alloc]
				     initWithFocusedViewRect: destinationRect ];
	
	NSData* data = [bitmap representationUsingType:NSPNGFileType properties:nil];
	[bitmap release];
	
	[[NSFileManager defaultManager]
	  createFileAtPath: outputFilePath
	  contents: data
	  attributes: nil ];
	
	[image unlockFocus];
	[image release];
	[pool release];
}

line
Updated $LastChangedDate: 2005-01-07 20:53:38 +0100 (Fri, 07 Jan 2005) $
line
Kristof Van Landschoot
Author

line
Summary: We need to get the images out of the mp3 files, they're in there somewhere. This section explains how to get them out.
line
Single-page Version
Copyright 2003-2004 Coin-C bvba. Questions, Comments, Corrections? Email cctunes@coin-c.com.