Skip to content

Instantly share code, notes, and snippets.

@earino
Created June 26, 2012 16:04
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save earino/2996703 to your computer and use it in GitHub Desktop.
Save earino/2996703 to your computer and use it in GitHub Desktop.
Snippet of code using Inline::C and leptonica for super duper fast image resizing
# stuff setting up moose and the environment omitted
sub BUILD {
my $self = shift;
my $application_environment = $ENV{'APPLICATION_ENVIRONMENT'};
my $conf = new Config::General($self->config_file);
my %config = $conf->getall;
my $environment = $config{'Transformer'}->{$application_environment};
$self->temp_dir($environment->{'temp_dir'});
$self->temp_file_template($environment->{'temp_file_template'});
$self->inline_c_inc($environment->{'inline_c_inc'});
$self->inline_c_auto_include($environment->{'inline_c_auto_include'});
$self->inline_c_libs($environment->{'inline_c_libs'});
$self->inline_c_build_directory($environment->{'inline_c_build_directory'});
}
=back
=head2 Access
=over 4
=item $image_transformer->transform(image_path => $path, x_scale => $xs, y_scale => $ys, return_type => $ret)
Transforms the image in path to the scale provided by x_scale and y_scale, and returns it as a return_type type image.
Return type myst be a string that contains either jpeg, jpg, gif, or png. Preferably in lower case. This code looks compilcated
in that the C source that is compiled is inlined as a HERE doc. This is done for performance purposes and reading it off a disk
every time it was called would just slow things down. We use the Inline::Bind method to do the actual inline magic.
=back
=cut
method transform (Str :$image_path, Int :$x_scale, Int :$y_scale, Str :$return_type) {
my $c_source = <<END;
SV* scale(char * image_path, int x_size, int y_size, char * temp_out, char * type) {
l_float32 scale_x, scale_y;
PIX *pixs, *pixd;
//read in the requested file FIXME
if ((pixs = pixRead(image_path)) == NULL) {
fprintf(stderr, "pixs not made from %s\\n", image_path);
return NULL;
}
if (-1 != x_size) {
scale_x = (l_float32) x_size / pixGetWidth(pixs);
}
if (-1 != y_size) {
scale_y = (l_float32) y_size / pixGetHeight(pixs);
}
if (-1 == x_size) {
scale_x = scale_y;
}
if (-1 == y_size) {
scale_y = scale_x;
}
if (-1 != x_size || -1 != y_size) {
pixd = pixScale(pixs, scale_x, scale_y);
}
else {
pixd = pixCopy(NULL, pixs);
}
l_uint8 *data;
size_t data_size;
if (0 == strcmp("jpeg", type) || 0 == strcmp("jpg", type)) {
pixWrite(temp_out, pixd, IFF_JFIF_JPEG);
}
else if (0 == strcmp("gif", type)) {
pixWrite(temp_out, pixd, IFF_GIF);
}
else if (0 == strcmp("png", type)) {
pixWrite(temp_out, pixd, IFF_PNG);
}
else if (0 == strcmp("tiff", type)) {
pixWrite(temp_out, pixd, IFF_TIFF);
}
SV* retval = newSVpvf(temp_out);
pixDestroy(&pixd);
pixDestroy(&pixs);
return retval;
}
END
if (! -e $self->inline_c_build_directory) {
make_path($self->inline_c_build_directory);
}
if (! -e $self->temp_dir) {
make_path($self->temp_dir);
}
Inline->bind(C => $c_source,
INC => $self->inline_c_inc,
AUTO_INCLUDE => $self->inline_c_auto_include,
LIBS => $self->inline_c_libs,
DIRECTORY => $self->inline_c_build_directory);
my (undef, $return_file_type) = split("/", $return_type);
my (undef, $filename) = tempfile($self->temp_file_template,
DIR => $self->temp_dir,
OPEN => 0,
SUFFIX => ".$return_file_type");
my $tmpfile = __PACKAGE__::scale($image_path, $x_scale, $y_scale, $filename, $return_file_type);
my $data = read_file( $tmpfile );
unlink $tmpfile;
return $data;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment