Imager release history. Older releases can be found in Changes.old
- - improved thread safety
- - the internal error stack and log file handle are now in a per-thread
- context object
- - JPEG now captures IPTC information in a thread-safe way
- - avoid globals where possible for warning capture in libtiff
- - use a mutex to avoid re-entering thread-unsafe giflib
- - use a mutex to avoid re-entering thread-unsafe tifflib
- - use a mutex to avoid re-entering thread-unsafe T1Lib
- - use a library handle per thread for freetype 2.
- - use an engine handle per thread for freetype 1.x.
-
- - T1:
- - improve error reporting
- - provide better control of the level of anti-aliasing
-
- - support for giflib 5.0.
- https://rt.cpan.org/Ticket/Display.html?id=79029
-
- - allow freetype-config to be found on cygwin
-
-Imager 0.92_01 - 18 Aug 2012
-==============
-
-This development release was a work in progress release of the thread
-safety changes:
-
-Development release, let's see what broke.
-
-This release is not Imager API binary compatible with older releases,
-if you have a module that uses Imager's API it will need to be
-reinstalled.
-
- - improved thread safety
- - the internal error stack and log file handle are now in a per-thread
- context object
- - JPEG now captures IPTC information in a thread-safe way
- - avoid globals where possible for warning capture in libtiff
- - avoid re-entering libtiff or giflib since they aren't thread safe
-
-This release was removed from CPAN after a short time.
-
Imager 0.92 - 14 Aug 2012
===========
-Imager-Font-FT2 0.85
-====================
-
- - improve thread safety
-
- - allow freetype-config to be found on cygwin
-
Imager-Font-FT2 0.85
====================
package Imager::Font::FT2;
use strict;
use Imager;
-use Scalar::Util ();
use vars qw($VERSION @ISA);
@ISA = qw(Imager::Font);
BEGIN {
- $VERSION = "0.86";
+ $VERSION = "0.85";
require XSLoader;
XSLoader::load('Imager::Font::FT2', $VERSION);
sub _draw {
my $self = shift;
-
- $self->_valid
- or return;
-
my %input = @_;
if (exists $input{channel}) {
i_ft2_cp($self->{id}, $input{image}{IMG}, $input{'x'}, $input{'y'},
my $self = shift;
my %input = @_;
- $self->_valid
- or return;
-
return i_ft2_bbox($self->{id}, $input{size}, $input{sizew}, $input{string},
$input{utf8});
}
sub dpi {
my $self = shift;
-
- $self->_valid
- or return;
-
my @old = i_ft2_getdpi($self->{id});
if (@_) {
my %hsh = @_;
sub hinting {
my ($self, %opts) = @_;
- $self->_valid
- or return;
-
i_ft2_sethinting($self->{id}, $opts{hinting} || 0);
}
sub _transform {
my $self = shift;
- $self->_valid
- or return;
-
my %hsh = @_;
my $matrix = $hsh{matrix} or return undef;
sub has_chars {
my ($self, %hsh) = @_;
- $self->_valid
- or return;
-
unless (defined $hsh{string} && length $hsh{string}) {
$Imager::ERRSTR = "No string supplied to \$font->has_chars()";
return;
sub face_name {
my ($self) = @_;
- $self->_valid
- or return;
-
i_ft2_face_name($self->{id});
}
sub glyph_names {
my ($self, %input) = @_;
- $self->_valid
- or return;
-
my $string = $input{string};
defined $string
or return Imager->_set_error("no string parameter passed to glyph_names");
sub is_mm {
my ($self) = @_;
- $self->_valid
- or return;
-
i_ft2_is_multiple_master($self->{id});
}
sub mm_axes {
my ($self) = @_;
- $self->_valid
- or return;
-
my ($num_axis, $num_design, @axes) =
i_ft2_get_multiple_masters($self->{id})
or return Imager->_set_error(Imager->_error_as_msg);
sub set_mm_coords {
my ($self, %opts) = @_;
- $self->_valid
- or return;
-
$opts{coords}
or return Imager->_set_error("Missing coords parameter");
ref($opts{coords}) && $opts{coords} =~ /ARRAY\(0x[\da-f]+\)$/
return 1;
}
-
-# objects may be invalidated on thread creation (or Win32 fork emulation)
-sub _valid {
- my $self = shift;
-
- unless ($self->{id} && Scalar::Util::blessed($self->{id})) {
- Imager->_set_error("font object was created in another thread");
- return;
- }
-
- return 1;
-}
-
1;
__END__
BOOT:
PERL_INITIALIZE_IMAGER_CALLBACKS;
- i_ft2_start();
MANIFEST.SKIP
README
t/t10ft2.t
-t/t20thread.t
typemap
$opts{PREREQ_PM} =
{
@Imager_req,
- 'Scalar::Util' => 1.00,
XSLoader => 0,
};
}
if ($^O eq 'MSWin32') {
push @exe_suffix, qw/.bat .cmd/;
}
- elsif ($^O eq 'cygwin') {
- push @exe_suffix, "";
- }
for my $dir (File::Spec->path) {
for my $suffix (@exe_suffix) {
static void ft2_push_message(int code);
-static void ft2_final(void *);
-
-static im_slot_t slot = -1;
-
-typedef struct {
- int initialized;
- FT_Library library;
- im_context_t ctx;
-} ft2_state;
+static int ft2_initialized = 0;
+static FT_Library library;
static i_img_dim i_min(i_img_dim a, i_img_dim b);
static i_img_dim i_max(i_img_dim a, i_img_dim b);
-void
-i_ft2_start(void) {
- if (slot == -1)
- slot = im_context_slot_new(ft2_final, "FT2");
-}
-
/*
=item i_ft2_init(void)
Initializes the Freetype 2 library.
-Returns ft2_state * on success or NULL on failure.
+Returns true on success, false on failure.
=cut
*/
-
-static ft2_state *
+int
i_ft2_init(void) {
FT_Error error;
- im_context_t ctx = im_get_context();
- ft2_state *ft2 = im_context_slot_get(ctx, slot);
-
- if (ft2 == NULL) {
- ft2 = mymalloc(sizeof(ft2_state));
- ft2->initialized = 0;
- ft2->library = NULL;
- ft2->ctx = ctx;
- im_context_slot_set(ctx, slot, ft2);
- mm_log((1, "created FT2 state %p for context %p\n", ft2, ctx));
- }
i_clear_error();
- if (!ft2->initialized) {
- error = FT_Init_FreeType(&ft2->library);
- if (error) {
- ft2_push_message(error);
- i_push_error(0, "Initializing Freetype2");
- return NULL;
- }
- mm_log((1, "initialized FT2 state %p\n", ft2));
-
- ft2->initialized = 1;
+ error = FT_Init_FreeType(&library);
+ if (error) {
+ ft2_push_message(error);
+ i_push_error(0, "Initializing Freetype2");
+ return 0;
}
- return ft2;
-}
-
-static void
-ft2_final(void *state) {
- ft2_state *ft2 = state;
-
- if (ft2->initialized) {
- mm_log((1, "finalizing FT2 state %p\n", state));
- FT_Done_FreeType(ft2->library);
- ft2->library = NULL;
- ft2->initialized = 0;
- }
+ ft2_initialized = 1;
- mm_log((1, "freeing FT2 state %p\n", state));
- myfree(state);
+ return 1;
}
struct FT2_Fonthandle {
FT_Face face;
- ft2_state *state;
int xdpi, ydpi;
int hint;
FT_Encoding encoding;
int i, j;
FT_Encoding encoding;
int score;
- ft2_state *ft2;
mm_log((1, "i_ft2_new(name %p, index %d)\n", name, index));
- if ((ft2 = i_ft2_init()) == NULL)
+ if (!ft2_initialized && !i_ft2_init())
return NULL;
i_clear_error();
- error = FT_New_Face(ft2->library, name, index, &face);
+ error = FT_New_Face(library, name, index, &face);
if (error) {
ft2_push_message(error);
i_push_error(error, "Opening face");
result = mymalloc(sizeof(FT2_Fonthandle));
result->face = face;
- result->state = ft2;
result->xdpi = result->ydpi = 72;
result->encoding = encoding;
if (xdpi > 0 && ydpi > 0) {
handle->xdpi = xdpi;
handle->ydpi = ydpi;
- return 1;
+ return 0;
}
else {
i_push_error(0, "resolutions must be positive");
typedef FT2_Fonthandle* Imager__Font__FT2x;
-extern void i_ft2_start(void);
+extern int i_ft2_init(void);
extern FT2_Fonthandle * i_ft2_new(const char *name, int index);
extern void i_ft2_destroy(FT2_Fonthandle *handle);
extern int i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi);
+++ /dev/null
-#!perl -w
-use strict;
-use Imager;
-
-use Config;
-my $loaded_threads;
-BEGIN {
- if ($Config{useithreads} && $] > 5.008007) {
- $loaded_threads =
- eval {
- require threads;
- threads->import;
- 1;
- };
- }
-}
-
-use Test::More;
-
-$Config{useithreads}
- or plan skip_all => "can't test Imager's lack of threads support with no threads";
-$] > 5.008007
- or plan skip_all => "require a perl with CLONE_SKIP to test Imager's lack of threads support";
-$loaded_threads
- or plan skip_all => "couldn't load threads";
-
-$INC{"Devel/Cover.pm"}
- and plan skip_all => "threads and Devel::Cover don't get along";
-
-# https://rt.cpan.org/Ticket/Display.html?id=65812
-# https://github.com/schwern/test-more/issues/labels/Test-Builder2#issue/100
-$Test::More::VERSION =~ /^2\.00_/
- and plan skip_all => "threads are hosed in 2.00_06 and presumably all 2.00_*";
-
-plan tests => 8;
-
-Imager->open_log(log => "testout/t20thread.log");
-
-my $ft1 = Imager::Font->new(file => "fontfiles/dodge.ttf", type => "ft2");
-ok($ft1, "make a font");
-ok($ft1->_valid, "and it's valid");
-my $ft2;
-
-my $thr = threads->create
- (
- sub {
- ok(!$ft1->_valid, "first font no longer valid");
- $ft2 = Imager::Font->new(file => "fontfiles/dodge.ttf", type => "ft2");
- ok($ft2, "make a new font in thread");
- ok($ft2->_valid, "and it's valid");
- 1;
- },
- );
-
-ok($thr->join, "join the thread");
-ok($ft1->_valid, "original font still valid in main thread");
-is($ft2, undef, "font created in thread shouldn't be set in main thread");
-
-Imager->close_log();
-Imager-File-GIF 0.85
-====================
-
- - add giflib 5.0 support.
- https://rt.cpan.org/Ticket/Display.html?id=79029
-
-Imager-File-GIF 0.84 - released with Imager 0.92_01
+Imager-File-GIF 0.84
====================
- giflib 4.2 eliminates the GIF_LIB_VERSION macro, handle that
use vars qw($VERSION @ISA);
BEGIN {
- $VERSION = "0.85";
+ $VERSION = "0.84";
require XSLoader;
XSLoader::load('Imager::File::GIF', $VERSION);
BOOT:
PERL_INITIALIZE_IMAGER_CALLBACKS;
PERL_INITIALIZE_IMAGER_PERL_CALLBACKS;
- i_init_gif();
inccheck => sub { -e File::Spec->catfile($_[0], "gif_lib.h") },
libbase => "gif",
testcode => _gif_test_code(),
- testcodeheaders => [ "stddef.h", "gif_lib.h", "stdio.h" ],
+ testcodeheaders => [ "gif_lib.h", "stdio.h" ],
incpath => \@incpaths,
libpath => \@libpaths,
);
#else
int ver_maj = GIFLIB_MAJOR;
int ver_min = GIFLIB_MINOR;
-int error;
#endif
-#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
-gf=DGifOpenFileName("testimg/expected.gif", &error);
-#else
gf=DGifOpenFileName("testimg/expected.gif");
-#endif
if (!gf) {
fprintf(stderr, "GIF: Cannot open testimg/expected.gif\n");
return 1;
fprintf(stderr, "GIF: bad screen description (%d x %d)\n", gf->SWidth, gf->SHeight);
return 1;
}
-#if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
-/* crashes in older versions of giflib, not used in giflib 5 */
+/* crashes in older versions of giflib */
EGifSetGifVersion("89a");
EGifSetGifVersion("87a");
-#endif
#ifdef GIF_LIB_VERSION
/* skip the " Version " */
=cut
*/
-#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
-#define myDGifOpen(userPtr, readFunc, Error) DGifOpen((userPtr), (readFunc), (Error))
-#define myEGifOpen(userPtr, readFunc, Error) EGifOpen((userPtr), (readFunc), (Error))
-#define myGifError(gif) ((gif)->Error)
-#define MakeMapObject GifMakeMapObject
-#define FreeMapObject GifFreeMapObject
-
-#define gif_mutex_lock()
-#define gif_mutex_unlock()
-#else
-static GifFileType *
-myDGifOpen(void *userPtr, InputFunc readFunc, int *error) {
- GifFileType *result = DGifOpen(userPtr, readFunc);
- if (!result)
- *error = GifLastError();
-
- return result;
-}
-static GifFileType *
-myEGifOpen(void *userPtr, OutputFunc outputFunc, int *error) {
- GifFileType *result = EGifOpen(userPtr, outputFunc);
- if (!result)
- *error = GifLastError();
-
- return result;
-}
-#define myGifError(gif) GifLastError()
-
-#define gif_mutex_lock() i_mutex_lock(mutex)
-#define gif_mutex_unlock() i_mutex_unlock(mutex)
-#define NEED_MUTEX
-#endif
-
static char const *gif_error_msg(int code);
-static void gif_push_error(int code);
+static void gif_push_error(void);
/* Make some variables global, so we could access them faster: */
-static const int
+static int
InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */
-#ifdef NEED_MUTEX
-static i_mutex_t mutex;
-#endif
-
-/*
-=item i_init_gif()
-
-Initialize GIF support.
-
-For versions of giflib that require it, create a mutex to avoid
-reentrancy.
-
-=cut
-*/
-
-void
-i_init_gif(void) {
-#ifdef NEED_MUTEX
- mutex = i_mutex_new();
-#endif
-}
static
void
GifByteType *Extension;
GifRowType GifRow;
- GifColorType *ColorMapEntry;
+ static GifColorType *ColorMapEntry;
i_color col;
mm_log((1,"i_readgif_low(GifFile %p, colour_table %p, colours %p)\n", GifFile, colour_table, colours));
/* Scan the content of the GIF file and load the image(s) in: */
do {
if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Unable to get record type");
if (colour_table && *colour_table) {
myfree(*colour_table);
switch (RecordType) {
case IMAGE_DESC_RECORD_TYPE:
if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Unable to get image descriptor");
if (colour_table && *colour_table) {
myfree(*colour_table);
for (Count = i = 0; i < 4; i++) for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) {
Count++;
if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Reading GIF line");
if (colour_table && *colour_table) {
myfree(*colour_table);
else {
for (i = 0; i < Height; i++) {
if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Reading GIF line");
if (colour_table && *colour_table) {
myfree(*colour_table);
case EXTENSION_RECORD_TYPE:
/* Skip any extension blocks in file: */
if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Reading extension record");
if (colour_table && *colour_table) {
myfree(*colour_table);
}
while (Extension != NULL) {
if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "reading next block of extension");
if (colour_table && *colour_table) {
myfree(*colour_table);
myfree(GifRow);
if (DGifCloseFile(GifFile) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Closing GIF file object");
if (colour_table && *colour_table) {
myfree(*colour_table);
Internal function called by i_readgif_multi_low() in error handling
*/
-static void
-free_images(i_img **imgs, int count) {
+static void free_images(i_img **imgs, int count) {
int i;
if (count) {
=cut
*/
-i_img **
-i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
+i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
i_img *img;
int i, j, Size, Width, Height, ExtCode, Count;
int ImageNum = 0, BackGround = 0, ColorMapSize = 0;
/* Scan the content of the GIF file and load the image(s) in: */
do {
if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Unable to get record type");
free_images(results, *count);
DGifCloseFile(GifFile);
switch (RecordType) {
case IMAGE_DESC_RECORD_TYPE:
if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Unable to get image descriptor");
free_images(results, *count);
DGifCloseFile(GifFile);
j += InterlacedJumps[i]) {
Count++;
if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Reading GIF line");
free_images(results, *count);
DGifCloseFile(GifFile);
else {
for (i = 0; i < Height; i++) {
if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Reading GIF line");
free_images(results, *count);
DGifCloseFile(GifFile);
/* giflib does't have an interface to skip the image data */
for (i = 0; i < Height; i++) {
if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Reading GIF line");
free_images(results, *count);
myfree(GifRow);
case EXTENSION_RECORD_TYPE:
/* Skip any extension blocks in file: */
if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Reading extension record");
free_images(results, *count);
myfree(GifRow);
if (ExtCode == 0xFF && *Extension == 11) {
if (memcmp(Extension+1, "NETSCAPE2.0", 11) == 0) {
if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "reading loop extension");
free_images(results, *count);
myfree(GifRow);
}
while (Extension != NULL) {
if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "reading next block of extension");
free_images(results, *count);
myfree(GifRow);
myfree(GifRow);
if (DGifCloseFile(GifFile) == GIF_ERROR) {
- gif_push_error(myGifError(GifFile));
+ gif_push_error();
i_push_error(0, "Closing GIF file object");
free_images(results, *count);
return NULL;
i_img **
i_readgif_multi_wiol(io_glue *ig, int *count) {
GifFileType *GifFile;
- i_img **result;
- int gif_error;
-
- gif_mutex_lock();
-
+
i_clear_error();
- if ((GifFile = myDGifOpen((void *)ig, io_glue_read_cb, &gif_error )) == NULL) {
- gif_push_error(gif_error);
+ if ((GifFile = DGifOpen((void *)ig, io_glue_read_cb )) == NULL) {
+ gif_push_error();
i_push_error(0, "Cannot create giflib callback object");
mm_log((1,"i_readgif_multi_wiol: Unable to open callback datasource.\n"));
- gif_mutex_unlock();
return NULL;
}
- result = i_readgif_multi_low(GifFile, count, -1);
-
- gif_mutex_unlock();
-
- return result;
+ return i_readgif_multi_low(GifFile, count, -1);
}
static int
i_img *
i_readgif_wiol(io_glue *ig, int **color_table, int *colors) {
GifFileType *GifFile;
- i_img *result;
- int gif_error;
-
- gif_mutex_lock();
i_clear_error();
- if ((GifFile = myDGifOpen((void *)ig, io_glue_read_cb, &gif_error )) == NULL) {
- gif_push_error(gif_error);
+ if ((GifFile = DGifOpen((void *)ig, io_glue_read_cb )) == NULL) {
+ gif_push_error();
i_push_error(0, "Cannot create giflib callback object");
mm_log((1,"i_readgif_wiol: Unable to open callback datasource.\n"));
- gif_mutex_unlock();
return NULL;
}
- result = i_readgif_low(GifFile, color_table, colors);
-
- gif_mutex_unlock();
-
- return result;
+ return i_readgif_low(GifFile, color_table, colors);
}
/*
i_img *
i_readgif_single_wiol(io_glue *ig, int page) {
GifFileType *GifFile;
- i_img *result;
- int gif_error;
i_clear_error();
if (page < 0) {
return NULL;
}
- gif_mutex_lock();
-
- if ((GifFile = myDGifOpen((void *)ig, io_glue_read_cb, &gif_error )) == NULL) {
- gif_push_error(gif_error);
+ if ((GifFile = DGifOpen((void *)ig, io_glue_read_cb )) == NULL) {
+ gif_push_error();
i_push_error(0, "Cannot create giflib callback object");
mm_log((1,"i_readgif_wiol: Unable to open callback datasource.\n"));
- gif_mutex_unlock();
return NULL;
}
- result = i_readgif_single_low(GifFile, page);
-
- gif_mutex_unlock();
-
- return result;
+ return i_readgif_single_low(GifFile, page);
}
/*
for (i = 0; i < 4; ++i) {
for (j = InterlacedOffset[i]; j < img->ysize; j += InterlacedJumps[i]) {
if (EGifPutLine(gf, data+j*img->xsize, img->xsize) == GIF_ERROR) {
- gif_push_error(myGifError(gf));
+ gif_push_error();
i_push_error(0, "Could not save image data:");
mm_log((1, "Error in EGifPutLine\n"));
EGifCloseFile(gf);
int y;
for (y = 0; y < img->ysize; ++y) {
if (EGifPutLine(gf, data, img->xsize) == GIF_ERROR) {
- gif_push_error(myGifError(gf));
+ gif_push_error();
i_push_error(0, "Could not save image data:");
mm_log((1, "Error in EGifPutLine\n"));
EGifCloseFile(gf);
=cut
*/
-
-static int
-do_gce(GifFileType *gf, i_img *img, int want_trans, int trans_index)
+static int do_gce(GifFileType *gf, i_img *img, int want_trans, int trans_index)
{
unsigned char gce[4] = {0};
int want_gce = 0;
}
if (want_gce) {
if (EGifPutExtension(gf, 0xF9, sizeof(gce), gce) == GIF_ERROR) {
- gif_push_error(myGifError(gf));
+ gif_push_error();
i_push_error(0, "Could not save GCE");
}
}
=cut
*/
-
-static int
-do_comments(GifFileType *gf, i_img *img) {
+static int do_comments(GifFileType *gf, i_img *img) {
int pos = -1;
while (i_tags_find(&img->tags, "gif_comment", pos+1, &pos)) {
=cut
*/
-
-static int
-do_ns_loop(GifFileType *gf, i_img *img)
+static int do_ns_loop(GifFileType *gf, i_img *img)
{
/* EGifPutExtension() doesn't appear to handle application
extension blocks in any way
if (i_tags_get_int(&img->tags, "gif_loop", 0, &loop_count)) {
unsigned char nsle[12] = "NETSCAPE2.0";
unsigned char subblock[3];
-
- subblock[0] = 1;
- subblock[1] = loop_count % 256;
- subblock[2] = loop_count / 256;
-
-#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
- if (EGifPutExtensionLeader(gf, APPLICATION_EXT_FUNC_CODE) == GIF_ERROR
- || EGifPutExtensionBlock(gf, 11, nsle) == GIF_ERROR
- || EGifPutExtensionBlock(gf, 3, subblock) == GIF_ERROR
- || EGifPutExtensionTrailer(gf) == GIF_ERROR) {
- gif_push_error(myGifError(gf));
- i_push_error(0, "writing loop extension");
- return 0;
- }
-
-#else
if (EGifPutExtensionFirst(gf, APPLICATION_EXT_FUNC_CODE, 11, nsle) == GIF_ERROR) {
- gif_push_error(myGifError(gf));
+ gif_push_error();
i_push_error(0, "writing loop extension");
return 0;
}
+ subblock[0] = 1;
+ subblock[1] = loop_count % 256;
+ subblock[2] = loop_count / 256;
if (EGifPutExtensionLast(gf, APPLICATION_EXT_FUNC_CODE, 3, subblock) == GIF_ERROR) {
- gif_push_error(myGifError(gf));
+ gif_push_error();
i_push_error(0, "writing loop extension sub-block");
return 0;
}
-#endif
}
return 1;
=cut
*/
-static ColorMapObject *
-make_gif_map(i_quantize *quant, i_img *img, int want_trans) {
+static ColorMapObject *make_gif_map(i_quantize *quant, i_img *img,
+ int want_trans) {
GifColorType colors[256];
int i;
int size = quant->mc_count;
map = MakeMapObject(map_size, colors);
mm_log((1, "XXX map is at %p and colors at %p\n", map, map->Colors));
if (!map) {
+ gif_push_error();
i_push_error(0, "Could not create color map object");
return NULL;
}
or install a less buggy giflib.
-This code is completely unnecessary in giflib 5
-
=cut
*/
-static void
-gif_set_version(i_quantize *quant, i_img **imgs, int count) {
-#if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
+static void gif_set_version(i_quantize *quant, i_img **imgs, int count) {
int need_89a = 0;
int temp;
int i;
EGifSetGifVersion("89a");
else
EGifSetGifVersion("87a");
-#endif
}
static int
myfree(localmaps);
myfree(glob_imgs);
quant->mc_colors = orig_colors;
- gif_push_error(myGifError(gf));
+ gif_push_error();
i_push_error(0, "Could not save screen descriptor");
FreeMapObject(map);
myfree(result);
myfree(localmaps);
myfree(glob_imgs);
quant->mc_colors = orig_colors;
- gif_push_error(myGifError(gf));
+ gif_push_error();
i_push_error(0, "Could not save image descriptor");
EGifCloseFile(gf);
mm_log((1, "Error in EGifPutImageDesc."));
myfree(localmaps);
myfree(glob_imgs);
quant->mc_colors = orig_colors;
- gif_push_error(myGifError(gf));
+ gif_push_error();
i_push_error(0, "Could not save image descriptor");
myfree(result);
if (map)
myfree(glob_colors);
myfree(localmaps);
myfree(glob_imgs);
- gif_push_error(myGifError(gf));
+ gif_push_error();
i_push_error(0, "Could not close GIF file");
mm_log((1, "Error in EGifCloseFile\n"));
return 0;
int count) {
GifFileType *GifFile;
int result;
- int gif_error;
-
- gif_mutex_lock();
i_clear_error();
gif_set_version(quant, imgs, count);
- if ((GifFile = myEGifOpen((void *)ig, io_glue_write_cb, &gif_error )) == NULL) {
- gif_push_error(gif_error);
+ if ((GifFile = EGifOpen((void *)ig, io_glue_write_cb )) == NULL) {
+ gif_push_error();
i_push_error(0, "Cannot create giflib callback object");
mm_log((1,"i_writegif_wiol: Unable to open callback datasource.\n"));
- gif_mutex_unlock();
return 0;
}
result = i_writegif_low(quant, GifFile, imgs, count);
- gif_mutex_unlock();
-
if (i_io_close(ig))
return 0;
Grabs the most recent giflib error code from GifLastError() and
returns a string that describes that error.
-Returns NULL for unknown error codes.
+The returned pointer points to a static buffer, either from a literal
+C string or a static buffer.
=cut
*/
-static char const *
-gif_error_msg(int code) {
-#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
- return GifErrorString(code);
-#else
+static char const *gif_error_msg(int code) {
+ static char msg[80];
+
switch (code) {
case E_GIF_ERR_OPEN_FAILED: /* should not see this */
return "Failed to open given file";
return "Unexpected EOF - invalid file";
default:
- return NULL;
- }
+#ifdef IMAGER_SNPRINTF
+ snprintf(msg, sizeof(msg), "Unknown giflib error code %d", code);
+#else
+ sprintf(msg, "Unknown giflib error code %d", code);
#endif
+ return msg;
+ }
}
/*
-=item gif_push_error(code)
+=item gif_push_error()
Utility function that takes the current GIF error code, converts it to
an error message and pushes it on the error stack.
=cut
*/
-static void
-gif_push_error(int code) {
- const char *msg = gif_error_msg(code);
- if (msg)
- i_push_error(code, msg);
- else
- i_push_errorf(code, "Unknown GIF error %d", code);
+static void gif_push_error(void) {
+ int code = GifLastError(); /* clears saved error */
+
+ i_push_error(code, gif_error_msg(code));
}
/*
+=head1 BUGS
+
+The Netscape loop extension isn't implemented. Giflib's extension
+writing code doesn't seem to support writing named extensions in this
+form.
+
+A bug in giflib is tickled by the i_writegif_callback(). This isn't a
+problem on ungiflib, but causes a SEGV on giflib. A patch is provided
+in t/t10formats.t
+
+The GIF file tag (GIF87a vs GIF89a) currently isn't set. Using the
+supplied interface in giflib 4.1.0 causes a SEGV in
+EGifSetGifVersion(). See L<gif_set_version> for an explanation.
+
=head1 AUTHOR
Arnar M. Hrafnkelsson, addi@umich.edu
-Tony Cook <tonyc@cpan.org>
-
=head1 SEE ALSO
perl(1), Imager(3)
#include "imext.h"
-void i_init_gif(void);
double i_giflib_version(void);
i_img *i_readgif_wiol(io_glue *ig, int **colour_table, int *colours);
i_img *i_readgif_single_wiol(io_glue *ig, int page);
($io, { make_colors=>'addi',
translate=>'closest',
transp=>'ordered',
- }, @imgs), "write from paletted")
- or diag(Imager->_error_as_msg());
+ }, @imgs), "write from paletted");
close FH;
# make sure nothing bad happened
L<Imager::Security> - brief security notes.
-=item *
-
-L<Imager::Threads> - brief information on working with threads.
-
=back
=head2 Basic Overview
text, measuring - L<Imager::Font/bounding_box()>, L<Imager::Font::BBox>
-threads - L<Imager::Threads>
-
tiles, color - L<Imager::Filters/mosaic>
transparent images - L<Imager::ImageTypes>,
writing an image to a file - L<Imager::Files>
+=head1 THREADS
+
+Imager doesn't support perl threads.
+
+Imager has limited code to prevent double frees if you create images,
+colors etc, and then create a thread, but has no code to prevent two
+threads entering Imager's error handling code, and none is likely to
+be added.
+
=head1 SUPPORT
The best place to get help with Imager is the mailing list.
#include "imperl.h"
-/*
-
-Context object management
-
-*/
-
-typedef im_context_t Imager__Context;
-
-#define im_context_DESTROY(ctx) im_context_refdec((ctx), "DESTROY")
-
-#ifdef PERL_IMPLICIT_CONTEXT
-
-#define MY_CXT_KEY "Imager::_context" XS_VERSION
-
-typedef struct {
- im_context_t ctx;
-} my_cxt_t;
-
-START_MY_CXT
-
-im_context_t fallback_context;
-
-static void
-start_context(pTHX) {
- dMY_CXT;
- MY_CXT.ctx = im_context_new();
- sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
-
- /* Ideally we'd free this reference, but the error message memory
- was never released on exit, so the associated memory here is reasonable
- to keep.
- With logging enabled we always need at least one context, since
- objects may be released fairly late and attempt to get the log file.
- */
- im_context_refinc(MY_CXT.ctx, "start_context");
- fallback_context = MY_CXT.ctx;
-}
-
-static im_context_t
-perl_get_context(void) {
- dTHX;
- dMY_CXT;
-
- return MY_CXT.ctx ? MY_CXT.ctx : fallback_context;
-}
-
-#else
-
-static im_context_t perl_context;
-
-static void
-start_context(pTHX) {
- perl_context = im_context_new();
- im_context_refinc(perl_context, "start_context");
-}
-
-static im_context_t
-perl_get_context(void) {
- return perl_context;
-}
-
-#endif
-
/* used to represent channel lists parameters */
typedef struct i_channel_list_tag {
int *channels;
}
}
+
/* I don't think ICLF_* names belong at the C interface
this makes the XS code think we have them, to let us avoid
putting function bodies in the XS code
#endif
-MODULE = Imager PACKAGE = Imager::Context PREFIX=im_context_
-
-void
-im_context_DESTROY(ctx)
- Imager::Context ctx
-
-#ifdef PERL_IMPLICIT_CONTEXT
-
-void
-im_context_CLONE(...)
- CODE:
- MY_CXT_CLONE;
- (void)items;
- /* the following sv_setref_pv() will free this inc */
- im_context_refinc(MY_CXT.ctx, "CLONE");
- MY_CXT.ctx = im_context_clone(MY_CXT.ctx, "CLONE");
- sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
-
-#endif
-
BOOT:
PERL_SET_GLOBAL_CALLBACKS;
PERL_PL_SET_GLOBAL_CALLBACKS;
-#ifdef PERL_IMPLICIT_CONTEXT
- {
- MY_CXT_INIT;
- (void)MY_CXT;
- }
-#endif
- start_context(aTHX);
- im_get_context = perl_get_context;
-#ifdef HAVE_LIBTT
- i_tt_start();
-#endif
use vars qw($VERSION @ISA);
BEGIN {
- $VERSION = "0.85";
+ $VERSION = "0.84";
require XSLoader;
XSLoader::load('Imager::File::JPEG', $VERSION);
#include <unistd.h>
#endif
#include <setjmp.h>
-#include <string.h>
#include "jpeglib.h"
#include "jerror.h"
#include <errno.h>
#include <stdlib.h>
+#include <stdio.h>
#include "imexif.h"
#define JPEG_APP13 0xED /* APP13 marker code */
static unsigned char fake_eoi[]={(JOCTET) 0xFF,(JOCTET) JPEG_EOI};
+/* Bad design right here */
+
+static int tlength=0;
+static char **iptc_text=NULL;
+
+
/* Source and Destination managers */
+
typedef struct {
struct jpeg_source_mgr pub; /* public fields */
io_glue *data;
typedef wiol_source_mgr *wiol_src_ptr;
typedef wiol_destination_mgr *wiol_dest_ptr;
+
/*
* Methods for io manager objects
*
dest->pub.next_output_byte = dest->buffer;
}
+LOCAL(unsigned int)
+jpeg_getc (j_decompress_ptr cinfo)
+/* Read next byte */
+{
+ struct jpeg_source_mgr * datasrc = cinfo->src;
+
+ if (datasrc->bytes_in_buffer == 0) {
+ if (! (*datasrc->fill_input_buffer) (cinfo))
+ { fprintf(stderr,"Jpeglib: cant suspend.\n"); exit(3); }
+ /* ERREXIT(cinfo, JERR_CANT_SUSPEND);*/
+ }
+ datasrc->bytes_in_buffer--;
+ return GETJOCTET(*datasrc->next_input_byte++);
+}
+
+METHODDEF(boolean)
+APP13_handler (j_decompress_ptr cinfo) {
+ INT32 length;
+ unsigned int cnt=0;
+
+ length = jpeg_getc(cinfo) << 8;
+ length += jpeg_getc(cinfo);
+ length -= 2; /* discount the length word itself */
+
+ tlength=length;
+
+ if ( ((*iptc_text)=mymalloc(length)) == NULL ) return FALSE;
+ while (--length >= 0) (*iptc_text)[cnt++] = jpeg_getc(cinfo);
+
+ return TRUE;
+}
+
METHODDEF(void)
my_output_message (j_common_ptr cinfo) {
char buffer[JMSG_LENGTH_MAX];
i_clear_error();
- *iptc_itext = NULL;
- *itlength = 0;
-
+ iptc_text = iptc_itext;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
jerr.pub.output_message = my_output_message;
if (src_set)
wiol_term_source(&cinfo);
jpeg_destroy_decompress(&cinfo);
+ *iptc_itext=NULL;
+ *itlength=0;
if (line_buffer)
myfree(line_buffer);
if (im)
}
jpeg_create_decompress(&cinfo);
- jpeg_save_markers(&cinfo, JPEG_APP13, 0xFFFF);
+ jpeg_set_marker_processor(&cinfo, JPEG_APP13, APP13_handler);
jpeg_save_markers(&cinfo, JPEG_APP1, 0xFFFF);
jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
jpeg_wiol_src(&cinfo, data, length);
else if (markerp->marker == JPEG_APP1 && !seen_exif) {
seen_exif = i_int_decode_exif(im, markerp->data, markerp->data_length);
}
- else if (markerp->marker == JPEG_APP13) {
- *iptc_itext = mymalloc(markerp->data_length);
- memcpy(*iptc_itext, markerp->data, markerp->data_length);
- *itlength = markerp->data_length;
- }
markerp = markerp->next;
}
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
+ *itlength=tlength;
i_tags_set(&im->tags, "i_format", "jpeg", 4);
color.c Color translation and handling
combine.im Channel combine
compose.im
-context.c
conv.im
convert.im
CountColor/CountColor.pm sample XS access to API
Flines/Makefile.PL
Flines/t/t00flines.t
flip.im
-fontft1.c
+font.c
fontfiles/dodge.ttf
fontfiles/ExistenceTest.ttf generated using pfaedit
fontfiles/ImUgly.ttf
FT2/Makefile.PL
FT2/README
FT2/t/t10ft2.t
-FT2/t/t20thread.t
FT2/typemap
gaussian.im
GIF/GIF.pm
lib/Imager/Regops.pm
lib/Imager/Security.pod
lib/Imager/Test.pm
-lib/Imager/Threads.pod
lib/Imager/Transform.pm
lib/Imager/Transformations.pod
lib/Imager/Tutorial.pod
MANIFEST.SKIP
map.c
maskimg.c
-mutexnull.c
-mutexpthr.c
-mutexwin.c
palimg.c
paste.im
plug.h
t/t81hlines.t Test hlines.c
t/t82inline.t Test Inline::C integration
t/t83extutil.t Test Imager::ExtUtils
-t/t84inlinectx.t
t/t90cc.t
t/t91pod.t Test POD with Test::Pod
t/t92samples.t
T1/t/t20oo.t
T1/T1.pm
T1/T1.xs
-T1/typemap
tags.c
testimg/alpha16.tga 16-bit/pixel TGA with alpha "channel" RT 32926
testimg/bad1oflow.bmp 1-bit/pixel, overflow integer on 32-bit machines
my @libpaths; # places to look for libraries
my $coverage; # build for coverage testing
my $assert; # build with assertions
-my $trace_context; # trace context management to stderr
GetOptions("help" => \$help,
"enable=s" => \@enable,
"disable=s" => \@disable,
"verbose|v" => \$VERBOSE,
"nolog" => \$NOLOG,
'coverage' => \$coverage,
- "assert|a" => \$assert,
- "tracecontext" => \$trace_context);
+ "assert|a" => \$assert);
setenv();
if ($^O eq 'hpux') { $OSLIBS .= ' -ldld'; }
if (defined $Config{'d_dlsymun'}) { $OSDEF .= ' -DDLSYMUN'; }
-my @objs = qw(Imager.o context.o draw.o polygon.o image.o io.o iolayer.o
- log.o gaussian.o conv.o pnm.o raw.o feat.o combine.o
+my @objs = qw(Imager.o draw.o polygon.o image.o io.o iolayer.o
+ log.o gaussian.o conv.o pnm.o raw.o feat.o font.o combine.o
filters.o dynaload.o stackmach.o datatypes.o
regmach.o trans2.o quant.o error.o convert.o
map.o tags.o palimg.o maskimg.o img8.o img16.o rotate.o
bmp.o tga.o color.o fills.o imgdouble.o limits.o hlines.o
imext.o scale.o rubthru.o render.o paste.o compose.o flip.o);
-if ($Config{useithreads}) {
- if ($Config{i_pthread}) {
- print "POSIX threads\n";
- push @objs, "mutexpthr.o";
- }
- elsif ($^O eq 'MSWin32') {
- print "Win32 threads\n";
- push @objs, "mutexwin.o";
- }
- else {
- print "Unsupported threading model\n";
- push @objs, "mutexnull.o";
- }
-}
-else {
- print "No threads\n";
- push @objs, "mutexnull.o";
-}
-
my @typemaps = qw(typemap.local typemap);
if ($] < 5.008) {
unshift @typemaps, "typemap.oldperl";
}
-if ($trace_context) {
- $CFLAGS .= " -DIMAGER_TRACE_CONTEXT";
-}
-
my %opts=
(
'NAME' => 'Imager',
&& !-e catfile($_[0], 'fterrors.h') },
libcheck=>sub { $_[0] eq "libttf$aext" or $_[0] eq "libttf.$lext" },
libfiles=>'-lttf',
- objfiles=>'fontft1.o',
+ objfiles=>'',
code => \&freetype1_probe,
docs=>q{
Truetype fonts are scalable fonts. They can include
-Imager::Font::T1 1.018
-======================
-
- - use mutexes to avoid re-entrancy into the thread-unsafe T1Lib
-
- - improve error handling and reporting
-
- - provide better control of the level of anti-aliasing
-
Imager::Font::T1 1.017
======================
t/t20oo.t
T1.pm
T1.xs
-typemap
@ISA = qw(Imager::Font);
BEGIN {
- $VERSION = "1.018";
+ $VERSION = "1.017";
require XSLoader;
XSLoader::load('Imager::Font::T1', $VERSION);
*_first = \&Imager::Font::_first;
-my $t1aa = 2;
+my $t1aa;
+
+# $T1AA is in there because for some reason (probably cache related) antialiasing
+# is a system wide setting in t1 lib.
+
+sub t1_set_aa_level {
+ if (!defined $t1aa or $_[0] != $t1aa) {
+ i_t1_set_aa($_[0]);
+ $t1aa=$_[0];
+ }
+}
sub new {
my $class = shift;
$hsh{afm} = 0;
}
- my $font = Imager::Font::T1xs->new($hsh{file},$hsh{afm});
- unless ($font) { # the low-level code may miss some error handling
+ my $id = i_t1_new($hsh{file},$hsh{afm});
+ unless ($id >= 0) { # the low-level code may miss some error handling
Imager->_set_error(Imager->_error_as_msg);
return;
}
return bless {
- t1font => $font,
+ id => $id,
aa => $hsh{aa} || 0,
file => $hsh{file},
type => 't1',
size => $hsh{size},
color => $hsh{color},
- t1aa => $t1aa,
}, $class;
}
sub _draw {
my $self = shift;
my %input = @_;
+ t1_set_aa_level($input{aa});
my $flags = '';
$flags .= 'u' if $input{underline};
$flags .= 's' if $input{strikethrough};
$flags .= 'o' if $input{overline};
- my $aa = $input{aa} ? $self->{t1aa} : 0;
if (exists $input{channel}) {
- $self->{t1font}->cp($input{image}{IMG}, $input{'x'}, $input{'y'},
- $input{channel}, $input{size},
+ i_t1_cp($input{image}{IMG}, $input{'x'}, $input{'y'},
+ $input{channel}, $self->{id}, $input{size},
$input{string}, length($input{string}), $input{align},
- $input{utf8}, $flags, $aa)
- or return;
+ $input{utf8}, $flags);
} else {
- $self->{t1font}->text($input{image}{IMG}, $input{'x'}, $input{'y'},
- $input{color}, $input{size},
+ i_t1_text($input{image}{IMG}, $input{'x'}, $input{'y'},
+ $input{color}, $self->{id}, $input{size},
$input{string}, length($input{string}),
- $input{align}, $input{utf8}, $flags, $aa)
- or return;
+ $input{align}, $input{utf8}, $flags);
}
return $self;
$flags .= 'u' if $input{underline};
$flags .= 's' if $input{strikethrough};
$flags .= 'o' if $input{overline};
- return $self->{t1font}->bbox($input{size}, $input{string},
+ return i_t1_bbox($self->{id}, $input{size}, $input{string},
length($input{string}), $input{utf8}, $flags);
}
$Imager::ERRSTR = "No string supplied to \$font->has_chars()";
return;
}
- return $self->{t1font}->has_chars($hsh{string},
- _first($hsh{'utf8'}, $self->{utf8}, 0));
+ return i_t1_has_chars($self->{id}, $hsh{string},
+ _first($hsh{'utf8'}, $self->{utf8}, 0));
}
sub utf8 {
sub face_name {
my ($self) = @_;
- return $self->{t1font}->face_name();
+ i_t1_face_name($self->{id});
}
sub glyph_names {
or return Imager->_set_error("no string parameter passed to glyph_names");
my $utf8 = _first($input{utf8} || 0);
- return $self->{t1font}->glyph_name($string, $utf8);
+ i_t1_glyph_name($self->{id}, $string, $utf8);
}
-sub set_aa_level {
- my ($self, $new_t1aa) = @_;
-
- if (!defined $new_t1aa ||
- ($new_t1aa != 1 && $new_t1aa != 2)) {
- Imager->_set_error("set_aa_level: parameter must be 1 or 2");
- return;
- }
-
- if (ref $self) {
- $self->{t1aa} = $new_t1aa;
- }
- else {
- $t1aa = $new_t1aa;
- }
-
- return 1;
-}
1;
Obviously, if you're calculating the bounding box the size of the line
is included in the box, and the line isn't drawn :)
-=head2 Anti-aliasing
-
-T1Lib supports multiple levels of anti-aliasing, by default, if you
-request anti-aliased output, Imager::Font::T1 will use the maximum
-level.
-
-You can override this with the set_t1_aa() method:
-
-=over
-
-=item set_aa_level()
-
-Usage:
-
- $font->set_aa_level(1);
- Imager::Font::T1->set_aa_level(2);
-
-Sets the T1Lib anti-aliasing level either for the specified font, or
-for new font objects.
-
-The only parameter must be 1 or 2.
-
-Returns true on success.
-
-=back
-
=head1 AUTHOR
Addi, Tony
DEFINE_IMAGER_CALLBACKS;
-typedef i_t1_font_t Imager__Font__T1xs;
-
-#define i_t1_DESTROY(font) i_t1_destroy(font)
-
MODULE = Imager::Font::T1 PACKAGE = Imager::Font::T1
undef_int
i_init_t1(t1log)
int t1log
-MODULE = Imager::Font::T1 PACKAGE = Imager::Font::T1xs PREFIX = i_t1_
+void
+i_t1_set_aa(st)
+ int st
-Imager::Font::T1xs
-i_t1_new(class,pfb,afm)
+int
+i_t1_new(pfb,afm)
char* pfb
char* afm
- C_ARGS:
- pfb, afm
-void
-i_t1_DESTROY(font)
- Imager::Font::T1xs font
+int
+i_t1_destroy(font_id)
+ int font_id
undef_int
-i_t1_cp(font,im,xb,yb,channel,points,str_sv, length(str),align,utf8=0,flags="",aa=1)
- Imager::Font::T1xs font
+i_t1_cp(im,xb,yb,channel,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
Imager::ImgRaw im
i_img_dim xb
i_img_dim yb
int channel
+ int fontnum
double points
SV* str_sv
int align
int utf8
char* flags
- int aa
PREINIT:
char *str;
STRLEN len;
utf8 = 1;
#endif
str = SvPV(str_sv, len);
- RETVAL = i_t1_cp(font, im, xb,yb,channel,points,str,len,align,
- utf8,flags,aa);
+ RETVAL = i_t1_cp(im, xb,yb,channel,fontnum,points,str,len,align,
+ utf8,flags);
OUTPUT:
RETVAL
void
i_t1_bbox(fontnum,point,str_sv,len_ignored,utf8=0,flags="")
- Imager::Font::T1xs fontnum
+ int fontnum
double point
SV* str_sv
int utf8
undef_int
-i_t1_text(font,im,xb,yb,cl,points,str_sv,length(str),align,utf8=0,flags="",aa=1)
- Imager::Font::T1xs font
+i_t1_text(im,xb,yb,cl,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
Imager::ImgRaw im
i_img_dim xb
i_img_dim yb
Imager::Color cl
+ int fontnum
double points
SV* str_sv
int align
int utf8
- const char* flags
- int aa
+ char* flags
PREINIT:
char *str;
STRLEN len;
utf8 = 1;
#endif
str = SvPV(str_sv, len);
- RETVAL = i_t1_text(font,im, xb,yb,cl,points,str,len,align,
- utf8,flags,aa);
+ RETVAL = i_t1_text(im, xb,yb,cl,fontnum,points,str,len,align,
+ utf8,flags);
OUTPUT:
RETVAL
void
-i_t1_has_chars(font, text_sv, utf8 = 0)
- Imager::Font::T1xs font
+i_t1_has_chars(handle, text_sv, utf8 = 0)
+ int handle
SV *text_sv
int utf8
PREINIT:
#endif
text = SvPV(text_sv, len);
work = mymalloc(len);
- count = i_t1_has_chars(font, text, len, utf8, work);
+ count = i_t1_has_chars(handle, text, len, utf8, work);
if (GIMME_V == G_ARRAY) {
EXTEND(SP, count);
-
for (i = 0; i < count; ++i) {
PUSHs(boolSV(work[i]));
}
myfree(work);
void
-i_t1_face_name(font)
- Imager::Font::T1xs font
+i_t1_face_name(handle)
+ int handle
PREINIT:
char name[255];
int len;
PPCODE:
- len = i_t1_face_name(font, name, sizeof(name));
+ len = i_t1_face_name(handle, name, sizeof(name));
if (len) {
EXTEND(SP, 1);
PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
}
void
-i_t1_glyph_name(font, text_sv, utf8 = 0)
- Imager::Font::T1xs font
+i_t1_glyph_name(handle, text_sv, utf8 = 0)
+ int handle
SV *text_sv
int utf8
PREINIT:
--len;
}
EXTEND(SP, 1);
- if (i_t1_glyph_name(font, ch, name, sizeof(name))) {
+ if (i_t1_glyph_name(handle, ch, name, sizeof(name))) {
PUSHs(sv_2mortal(newSVpv(name, 0)));
}
else {
BOOT:
PERL_INITIALIZE_IMAGER_CALLBACKS;
- i_t1_start();
\ No newline at end of file
static int t1_get_flags(char const *flags);
static char *t1_from_utf8(char const *in, size_t len, int *outlen);
-static undef_int i_init_t1_low(int t1log);
+
static void t1_push_error(void);
-static void i_t1_set_aa(int st);
static int t1_active_fonts = 0;
static int t1_initialized = 0;
-static int t1_aa = 0;
-
-struct i_t1_font_tag {
- int font_id;
-};
-
-static i_mutex_t mutex;
-
-/*
-=item i_t1_start()
-
-Initialize the font driver. This does not actually initialize T1Lib,
-it just allocates the mutex we use to gate access to it.
-
-=cut
-*/
-
-void
-i_t1_start(void) {
- mutex = i_mutex_new();
-}
/*
=item i_init_t1(t1log)
undef_int
i_init_t1(int t1log) {
- undef_int result;
- i_mutex_lock(mutex);
-
- result = i_init_t1_low(t1log);
-
- i_mutex_unlock(mutex);
-
- return result;
-}
-
-static undef_int
-i_init_t1_low(int t1log) {
int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
-
- mm_log((1,"init_t1(%d)\n", t1log));
+ mm_log((1,"init_t1()\n"));
i_clear_error();
return(1);
}
T1_SetLogLevel(T1LOG_DEBUG);
+ i_t1_set_aa(1); /* Default Antialias value */
++t1_initialized;
void
i_close_t1(void) {
- i_mutex_lock(mutex);
T1_CloseLib();
t1_initialized = 0;
- i_mutex_unlock(mutex);
}
=cut
*/
-i_t1_font_t
+int
i_t1_new(char *pfb,char *afm) {
int font_id;
- i_t1_font_t font;
-
- i_mutex_lock(mutex);
i_clear_error();
- if (!t1_initialized && i_init_t1_low(0)) {
- i_mutex_unlock(mutex);
- return NULL;
- }
+ if (!t1_initialized && i_init_t1(0))
+ return -1;
mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
font_id = T1_AddFont(pfb);
if (font_id<0) {
mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
t1_push_error();
- i_mutex_unlock(mutex);
- return NULL;
+ return font_id;
}
if (afm != NULL) {
t1_push_error();
i_push_error(0, "loading font");
T1_DeleteFont(font_id);
- i_mutex_unlock(mutex);
- return NULL;
+ return -1;
}
++t1_active_fonts;
- i_mutex_unlock(mutex);
-
- font = mymalloc(sizeof(*font));
- font->font_id = font_id;
-
- mm_log((1, "i_t1_new() -> %p (%d)\n", font, font_id));
+ mm_log((1, "i_t1_new() -> %d\n", font_id));
- return font;
+ return font_id;
}
/*
-=item i_t1_destroy(font)
+=item i_t1_destroy(font_id)
Frees resources for a t1 font with given font id.
- font - font to free
+ font_id - number of the font to free
=cut
*/
int
-i_t1_destroy(i_t1_font_t font) {
- int result;
-
- i_mutex_lock(mutex);
-
- mm_log((1,"i_t1_destroy(font %p (%d))\n", font, font->font_id));
+i_t1_destroy(int font_id) {
+ mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
--t1_active_fonts;
- result = T1_DeleteFont(font->font_id);
- myfree(font);
-
- i_mutex_unlock(mutex);
-
- return result;
+ return T1_DeleteFont(font_id);
}
st - 0 = NONE, 1 = LOW, 2 = HIGH.
-Must be called with the mutex locked.
-
=cut
*/
-static void
+void
i_t1_set_aa(int st) {
int i;
unsigned long cst[17];
-
- if (t1_aa == st)
- return;
-
switch(st) {
case 0:
T1_AASetBitsPerPixel( 8 );
T1_AAHSetGrayValues( cst );
mm_log((1,"setting T1 antialias to high\n"));
}
-
- t1_aa = st;
}
/*
-=item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align,aa)
+=item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align)
Interface to text rendering into a single channel in an image
str - string to render
len - string length
align - (0 - top of font glyph | 1 - baseline )
- aa - anti-aliasing level
=cut
*/
undef_int
-i_t1_cp(i_t1_font_t font, i_img *im,i_img_dim xb,i_img_dim yb,int channel,double points,char* str,size_t len,int align, int utf8, char const *flags, int aa) {
+i_t1_cp(i_img *im,i_img_dim xb,i_img_dim yb,int channel,int fontnum,double points,char* str,size_t len,int align, int utf8, char const *flags) {
GLYPH *glyph;
int xsize,ysize,x,y;
i_color val;
int mod_flags = t1_get_flags(flags);
- int fontnum = font->font_id;
unsigned int ch_mask_store;
- i_clear_error();
-
- mm_log((1, "i_t1_cp(font %p (%d), im %p, (xb,yb)=" i_DFp ", channel %d, points %g, str %p, len %u, align %d, utf8 %d, flags '%s', aa %d)\n",
- font, fontnum, im, i_DFcp(xb, yb), channel, points, str, (unsigned)len, align, utf8, flags, aa));
-
- if (im == NULL) {
- mm_log((1,"i_t1_cp: Null image in input\n"));
- i_push_error(0, "null image");
- return(0);
- }
-
- i_mutex_lock(mutex);
-
- i_t1_set_aa(aa);
+ if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
if (utf8) {
int worklen;
else {
glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
}
- if (glyph == NULL) {
- t1_push_error();
- i_push_error(0, "i_t1_cp: T1_AASetString failed");
- i_mutex_unlock(mutex);
+ if (glyph == NULL)
return 0;
- }
mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
}
im->ch_mask=ch_mask_store;
-
- i_mutex_unlock(mutex);
-
return 1;
}
*/
int
-i_t1_bbox(i_t1_font_t font, double points,const char *str,size_t len, i_img_dim cords[6], int utf8,char const *flags) {
+i_t1_bbox(int fontnum, double points,const char *str,size_t len, i_img_dim cords[6], int utf8,char const *flags) {
BBox bbox;
BBox gbbox;
int mod_flags = t1_get_flags(flags);
i_img_dim advance;
- int fontnum = font->font_id;
- int space_position;
-
- i_mutex_lock(mutex);
-
- space_position = T1_GetEncodingIndex(fontnum, "space");
+ int space_position = T1_GetEncodingIndex(fontnum, "space");
- mm_log((1,"i_t1_bbox(font %p (%d),points %.2f,str '%.*s', len %d)\n",font, fontnum,points,len,str,len));
+ mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
if (len == 0) {
cords[BBOX_RIGHT_BEARING] =
cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
- i_mutex_unlock(mutex);
-
return BBOX_RIGHT_BEARING+1;
}
/*
-=item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align, aa)
+=item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align)
Interface to text rendering in a single color onto an image
str - char pointer to string to render
len - string length
align - (0 - top of font glyph | 1 - baseline )
- aa - anti-aliasing level
=cut
*/
undef_int
-i_t1_text(i_t1_font_t font, i_img *im, i_img_dim xb, i_img_dim yb,const i_color *cl, double points,const char* str,size_t len,int align, int utf8, char const *flags, int aa) {
+i_t1_text(i_img *im, i_img_dim xb, i_img_dim yb,const i_color *cl,int fontnum, double points,const char* str,size_t len,int align, int utf8, char const *flags) {
GLYPH *glyph;
int xsize,ysize,y;
int mod_flags = t1_get_flags(flags);
i_render *r;
- int fontnum = font->font_id;
- mm_log((1, "i_t1_text(font %p (%d), im %p, (xb,yb)=" i_DFp ", cl (%d,%d,%d,%d), points %g, str %p, len %u, align %d, utf8 %d, flags '%s', aa %d)\n",
- font, fontnum, im, i_DFcp(xb, yb), cl->rgba.r, cl->rgba.g, cl->rgba.b, cl->rgba.a, points, str, (unsigned)len, align, utf8, flags, aa));
-
- i_clear_error();
-
- if (im == NULL) {
- i_push_error(0, "null image");
- mm_log((1,"i_t1_text: Null image in input\n"));
- return(0);
- }
-
- i_mutex_lock(mutex);
-
- i_t1_set_aa(aa);
+ if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
if (utf8) {
int worklen;
/* T1_AASetString() accepts a char * not a const char */
glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
}
- if (glyph == NULL) {
- mm_log((1, "T1_AASetString failed\n"));
- t1_push_error();
- i_push_error(0, "i_t1_text(): T1_AASetString failed");
- i_mutex_unlock(mutex);
+ if (glyph == NULL)
return 0;
- }
mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
i_render_color(r, xb, yb+y, xsize, (unsigned char *)glyph->bits+y*xsize, cl);
}
i_render_delete(r);
-
- i_mutex_unlock(mutex);
return 1;
}
*/
int
-i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8,
+i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
char *out) {
int count = 0;
- int font_num = font->font_id;
- i_mutex_lock(mutex);
-
mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %d, utf8 %d)\n",
font_num, text, len, utf8));
i_clear_error();
if (T1_LoadFont(font_num)) {
t1_push_error();
- i_mutex_unlock(mutex);
return 0;
}
c = i_utf8_advance(&text, &len);
if (c == ~0UL) {
i_push_error(0, "invalid UTF8 character");
- i_mutex_unlock(mutex);
return 0;
}
}
++count;
}
- i_mutex_unlock(mutex);
-
return count;
}
/*
-=item i_t1_face_name(font, name_buf, name_buf_size)
+=item i_t1_face_name(font_num, name_buf, name_buf_size)
Copies the face name of the given C<font_num> to C<name_buf>. Returns
the number of characters required to store the name (which can be
*/
int
-i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size) {
+i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size) {
char *name;
- int font_num = font->font_id;
-
- i_mutex_lock(mutex);
T1_errno = 0;
if (T1_LoadFont(font_num)) {
t1_push_error();
- i_mutex_unlock(mutex);
return 0;
}
name = T1_GetFontName(font_num);
if (name) {
- size_t len = strlen(name);
strncpy(name_buf, name, name_buf_size);
name_buf[name_buf_size-1] = '\0';
- i_mutex_unlock(mutex);
- return len + 1;
+ return strlen(name) + 1;
}
else {
t1_push_error();
- i_mutex_unlock(mutex);
return 0;
}
}
int
-i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf,
+i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf,
size_t name_buf_size) {
char *name;
- int font_num = font->font_id;
- i_mutex_lock(mutex);
i_clear_error();
if (ch > 0xFF) {
- i_mutex_unlock(mutex);
return 0;
}
if (T1_LoadFont(font_num)) {
t1_push_error();
- i_mutex_unlock(mutex);
return 0;
}
name = T1_GetCharName(font_num, (unsigned char)ch);
if (name) {
if (strcmp(name, ".notdef")) {
- size_t len = strlen(name);
strncpy(name_buf, name, name_buf_size);
name_buf[name_buf_size-1] = '\0';
- i_mutex_unlock(mutex);
- return len + 1;
+ return strlen(name) + 1;
}
else {
- i_mutex_unlock(mutex);
return 0;
}
}
else {
t1_push_error();
- i_mutex_unlock(mutex);
return 0;
}
}
#ifdef T1ERR_SCAN_FONT_FORMAT
case T1ERR_SCAN_FONT_FORMAT:
- i_push_error(T1ERR_SCAN_FONT_FORMAT, "Attempt to Load Multiple Master Font");
+ i_push_error(T1ERR_SCAN_FONT_FORMAT, "SCAN_FONT_FORMAT");
break;
#endif
#ifdef T1ERR_SCAN_FILE_OPEN_ERR
case T1ERR_SCAN_FILE_OPEN_ERR:
- i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "Type 1 Font File Open Error");
+ i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "SCAN_FILE_OPEN_ERR");
break;
#endif
#ifdef T1ERR_SCAN_OUT_OF_MEMORY
case T1ERR_SCAN_OUT_OF_MEMORY:
- i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "Virtual Memory Exceeded");
+ i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "SCAN_OUT_OF_MEMORY");
break;
#endif
#ifdef T1ERR_SCAN_ERROR
case T1ERR_SCAN_ERROR:
- i_push_error(T1ERR_SCAN_ERROR, "Syntactical Error Scanning Font File");
+ i_push_error(T1ERR_SCAN_ERROR, "SCAN_ERROR");
break;
#endif
#ifdef T1ERR_SCAN_FILE_EOF
case T1ERR_SCAN_FILE_EOF:
- i_push_error(T1ERR_SCAN_FILE_EOF, "Premature End of Font File Encountered");
+ i_push_error(T1ERR_SCAN_FILE_EOF, "SCAN_FILE_EOF");
break;
#endif
#ifdef T1ERR_PATH_ERROR
case T1ERR_PATH_ERROR:
- i_push_error(T1ERR_PATH_ERROR, "Path Construction Error");
+ i_push_error(T1ERR_PATH_ERROR, "PATH_ERROR");
break;
#endif
#ifdef T1ERR_PARSE_ERROR
case T1ERR_PARSE_ERROR:
- i_push_error(T1ERR_PARSE_ERROR, "Font is Corrupt");
+ i_push_error(T1ERR_PARSE_ERROR, "PARSE_ERROR");
break;
#endif
#ifdef T1ERR_TYPE1_ABORT
case T1ERR_TYPE1_ABORT:
- i_push_error(T1ERR_TYPE1_ABORT, "Rasterization Aborted");
+ i_push_error(T1ERR_TYPE1_ABORT, "TYPE1_ABORT");
break;
#endif
#ifdef T1ERR_INVALID_FONTID
case T1ERR_INVALID_FONTID:
- i_push_error(T1ERR_INVALID_FONTID, "Font ID Invalid in this Context");
+ i_push_error(T1ERR_INVALID_FONTID, "INVALID_FONTID");
break;
#endif
#ifdef T1ERR_INVALID_PARAMETER
case T1ERR_INVALID_PARAMETER:
- i_push_error(T1ERR_INVALID_PARAMETER, "Invalid Argument in Function Call");
+ i_push_error(T1ERR_INVALID_PARAMETER, "INVALID_PARAMETER");
break;
#endif
#ifdef T1ERR_OP_NOT_PERMITTED
case T1ERR_OP_NOT_PERMITTED:
- i_push_error(T1ERR_OP_NOT_PERMITTED, "Operation not Permitted");
+ i_push_error(T1ERR_OP_NOT_PERMITTED, "OP_NOT_PERMITTED");
break;
#endif
#ifdef T1ERR_ALLOC_MEM
case T1ERR_ALLOC_MEM:
- i_push_error(T1ERR_ALLOC_MEM, "Memory Allocation Error");
+ i_push_error(T1ERR_ALLOC_MEM, "ALLOC_MEM");
break;
#endif
#ifdef T1ERR_FILE_OPEN_ERR
case T1ERR_FILE_OPEN_ERR:
- i_push_error(T1ERR_FILE_OPEN_ERR, "Error Opening File");
+ i_push_error(T1ERR_FILE_OPEN_ERR, "FILE_OPEN_ERR");
break;
#endif
#ifdef T1ERR_UNSPECIFIED
case T1ERR_UNSPECIFIED:
- i_push_error(T1ERR_UNSPECIFIED, "Unspecified T1Lib Error");
+ i_push_error(T1ERR_UNSPECIFIED, "UNSPECIFIED");
break;
#endif
#ifdef T1ERR_NO_AFM_DATA
case T1ERR_NO_AFM_DATA:
- i_push_error(T1ERR_NO_AFM_DATA, "Missing AFM Data");
+ i_push_error(T1ERR_NO_AFM_DATA, "NO_AFM_DATA");
break;
#endif
#ifdef T1ERR_X11
case T1ERR_X11:
- i_push_error(T1ERR_X11, "X11 Interface Error");
+ i_push_error(T1ERR_X11, "X11");
break;
#endif
#ifdef T1ERR_COMPOSITE_CHAR
case T1ERR_COMPOSITE_CHAR:
- i_push_error(T1ERR_COMPOSITE_CHAR, "Missing Component of Composite Character");
- break;
-#endif
-
-#ifdef T1ERR_SCAN_ENCODING
- case T1ERR_SCAN_ENCODING:
- i_push_error(T1ERR_SCAN_ENCODING, "Error Scanning Encoding File");
+ i_push_error(T1ERR_COMPOSITE_CHAR, "COMPOSITE_CHAR");
break;
#endif
#include "imdatatypes.h"
-typedef struct i_t1_font_tag *i_t1_font_t;
-
-extern void
-i_t1_start(void);
-
extern undef_int
i_init_t1(int t1log);
extern void
i_close_t1(void);
-extern i_t1_font_t
+extern int
i_t1_new(char *pfb,char *afm);
extern int
-i_t1_destroy(i_t1_font_t font);
+i_t1_destroy(int font_id);
+
+extern void
+i_t1_set_aa(int st);
extern undef_int
-i_t1_cp(i_t1_font_t font, i_img *im,i_img_dim xb,i_img_dim yb,int channel,double points,char* str,size_t len,int align, int utf8, char const *flags, int aa);
+i_t1_cp(i_img *im,i_img_dim xb,i_img_dim yb,int channel,int fontnum,double points,char* str,size_t len,int align, int utf8, char const *flags);
extern int
-i_t1_bbox(i_t1_font_t font,double points,const char *str,size_t len,i_img_dim *cords, int utf8,char const *flags);
+i_t1_bbox(int fontnum,double points,const char *str,size_t len,i_img_dim *cords, int utf8,char const *flags);
extern undef_int
-i_t1_text(i_t1_font_t font, i_img *im,i_img_dim xb,i_img_dim yb,const i_color *cl,double points,const char* str,size_t len,int align, int utf8, char const *flags, int aa);
+i_t1_text(i_img *im,i_img_dim xb,i_img_dim yb,const i_color *cl,int fontnum,double points,const char* str,size_t len,int align, int utf8, char const *flags);
extern int
-i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8,
+i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
char *out);
extern int
-i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size);
+i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size);
extern int
-i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf,
+i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf,
size_t name_buf_size);
#endif
use strict;
use Test::More;
use Imager ':all';
-use Imager::Test qw(diff_text_with_nul is_color3 is_image isnt_image);
+use Imager::Test qw(diff_text_with_nul is_color3);
use Imager::Font::T1;
use Cwd qw(getcwd abs_path);
#$Imager::DEBUG=1;
-plan tests => 108;
+plan tests => 97;
ok($Imager::formats{t1}, "must have t1");
init(t1log=>0);
unlink "t1lib.log";
- my $fnum=Imager::Font::T1xs->new($fontname_pfb,$fontname_afm); # this will load the pfb font
+ my $fnum=Imager::Font::T1::i_t1_new($fontname_pfb,$fontname_afm); # this will load the pfb font
unless (ok($fnum >= 0, "load font $fontname_pfb")) {
skip("without the font I can't do a thing", 90);
}
my $bgcolor=Imager::Color->new(255,0,0,0);
my $overlay=Imager::ImgRaw::new(200,70,3);
- ok($fnum->cp($overlay,5,50,1,50.0,'XMCLH',5,1), "i_t1_cp");
+ ok(Imager::Font::T1::i_t1_cp($overlay,5,50,1,$fnum,50.0,'XMCLH',5,1), "i_t1_cp");
i_line($overlay,0,50,100,50,$bgcolor,1);
- my @bbox=$fnum->bbox(50.0,'XMCLH',5);
+ my @bbox=Imager::Font::T1::i_t1_bbox(0,50.0,'XMCLH',5);
is(@bbox, 8, "i_t1_bbox");
print "# bbox: ($bbox[0], $bbox[1]) - ($bbox[2], $bbox[3])\n";
$bgcolor=Imager::Color::set($bgcolor,200,200,200,0);
my $backgr=Imager::ImgRaw::new(280,300,3);
- ok($fnum->text($backgr,10,100,$bgcolor,150.0,'test',4,1,2), "i_t1_text");
+ Imager::Font::T1::i_t1_set_aa(2);
+ ok(Imager::Font::T1::i_t1_text($backgr,10,100,$bgcolor,$fnum,150.0,'test',4,1), "i_t1_text");
# "UTF8" tests
# for perl < 5.6 we can hand-encode text
my $text = pack("C*", 0x41, 0xC2, 0xA1, 0xE2, 0x80, 0x90, 0x41);
my $alttext = "A\xA1A";
- my @utf8box = $fnum->bbox(50.0, $text, length($text), 1);
+ my @utf8box = Imager::Font::T1::i_t1_bbox($fnum, 50.0, $text, length($text), 1);
is(@utf8box, 8, "utf8 bbox element count");
- my @base = $fnum->bbox(50.0, $alttext, length($alttext), 0);
+ my @base = Imager::Font::T1::i_t1_bbox($fnum, 50.0, $alttext, length($alttext), 0);
is(@base, 8, "alt bbox element count");
my $maxdiff = $fontname_pfb eq $deffont ? 0 : $base[2] / 3;
print "# (@utf8box vs @base)\n";
"compare box sizes $utf8box[2] vs $base[2] (maxerror $maxdiff)");
# hand-encoded UTF8 drawing
- ok($fnum->text($backgr, 10, 140, $bgcolor, 32, $text, length($text), 1,1), "draw hand-encoded UTF8");
+ ok(Imager::Font::T1::i_t1_text($backgr, 10, 140, $bgcolor, $fnum, 32, $text, length($text), 1,1), "draw hand-encoded UTF8");
- ok($fnum->cp($backgr, 80, 140, 1, 32, $text, length($text), 1, 1),
+ ok(Imager::Font::T1::i_t1_cp($backgr, 80, 140, 1, $fnum, 32, $text, length($text), 1, 1),
"cp hand-encoded UTF8");
# ok, try native perl UTF8 if available
# versions
eval q{$text = "A\xA1\x{2010}A"}; # A, a with ogonek, HYPHEN, A in our test font
#$text = "A".chr(0xA1).chr(0x2010)."A"; # this one works too
- ok($fnum->text($backgr, 10, 180, $bgcolor, 32, $text, length($text), 1),
+ ok(Imager::Font::T1::i_t1_text($backgr, 10, 180, $bgcolor, $fnum, 32, $text, length($text), 1),
"draw UTF8");
- ok($fnum->cp($backgr, 80, 180, 1, 32, $text, length($text), 1),
+ ok(Imager::Font::T1::i_t1_cp($backgr, 80, 180, 1, $fnum, 32, $text, length($text), 1),
"cp UTF8");
- @utf8box = $fnum->bbox(50.0, $text, length($text), 0);
+ @utf8box = Imager::Font::T1::i_t1_bbox($fnum, 50.0, $text, length($text), 0);
is(@utf8box, 8, "native utf8 bbox element count");
ok(abs($utf8box[2] - $base[2]) <= $maxdiff,
"compare box sizes native $utf8box[2] vs $base[2] (maxerror $maxdiff)");
eval q{$text = "A\xA1\xA2\x01\x1F\x{0100}A"};
- ok($fnum->text($backgr, 10, 220, $bgcolor, 32, $text, 0, 1, 0, "uso"),
+ ok(Imager::Font::T1::i_t1_text($backgr, 10, 220, $bgcolor, $fnum, 32, $text, 0, 1, 0, "uso"),
"more complex output");
}
i_writeppm_wiol($backgr, $IO);
close(FH);
- undef $fnum;
+ my $rc=Imager::Font::T1::i_t1_destroy($fnum);
+ unless (ok($rc >= 0, "i_t1_destroy")) {
+ print "# i_t1_destroy failed: rc=$rc\n";
+ }
+
+ print "# debug: ",join(" x ",Imager::Font::T1::i_t1_bbox(0,50,"eses",4) ),"\n";
+ print "# debug: ",join(" x ",Imager::Font::T1::i_t1_bbox(0,50,"llll",4) ),"\n";
# character existance tests - uses the special ExistenceTest font
my $exists_font = 'fontfiles/ExistenceTest.pfb';
-e $exists_font or die "$exists_font not found";
- my $font_num = Imager::Font::T1xs->new($exists_font, $exists_afm);
+ my $font_num = Imager::Font::T1::i_t1_new($exists_font, $exists_afm);
SKIP: {
ok($font_num >= 0, 'loading test font')
or skip('Could not load test font', 6);
# first the list interface
- my @exists = $font_num->has_chars("!A");
+ my @exists = Imager::Font::T1::i_t1_has_chars($font_num, "!A");
is(@exists, 2, "return count from has_chars");
ok($exists[0], "we have an exclamation mark");
ok(!$exists[1], "we have no uppercase A");
# then the scalar interface
- my $exists = $font_num->has_chars("!A");
+ my $exists = Imager::Font::T1::i_t1_has_chars($font_num, "!A");
is(length($exists), 2, "return scalar length");
ok(ord(substr($exists, 0, 1)), "we have an exclamation mark");
ok(!ord(substr($exists, 1, 1)), "we have no upper-case A");
- undef $font_num;
+ Imager::Font::T1::i_t1_destroy($font_num);
}
my $font = Imager::Font->new(file=>$exists_font, type=>'t1');
isnt($bbox[2], $bbox[5], "different advance to pos_width");
# names
- my $face_name = $font->{t1font}->face_name();
+ my $face_name = Imager::Font::T1::i_t1_face_name($font->{id});
print "# face $face_name\n";
is($face_name, 'ExistenceTest', "face name");
$face_name = $font->face_name;
ok($font, "found font by drive relative path")
or print "# path $drive_path\n";
}
-
- {
- Imager->log("Testing aa levels", 1);
- my $f1 = Imager::Font->new(file => $deffont, type => "t1");
- is($f1->{t1aa}, 2, "should have default aa level");
- my $imbase = Imager->new(xsize => 100, ysize => 20);
- ok($imbase->string(text => "test", size => 18, x => 5, y => 18,
- color => "#FFF", font => $f1, aa => 1),
- "draw text with def aa level");
- ok(Imager::Font::T1->set_aa_level(1), "set aa level to 1");
- my $f2 = Imager::Font->new(file => $deffont, type => "t1");
- is($f2->{t1aa}, 1, "new font has new aa level");
- my $imaa1 = Imager->new(xsize => 100, ysize => 20);
- ok($imaa1->string(text => "test", size => 18, x => 5, y => 18,
- color => "#FFF", font => $f2, aa => 1),
- "draw text with non-def aa level");
- isnt_image($imbase, $imaa1, "images should differ");
- ok($f2->set_aa_level(2), "set aa level of font");
- is($f2->{t1aa}, 2, "check new aa level");
- my $imaa2 = Imager->new(xsize => 100, ysize => 20);
- ok($imaa2->string(text => "test", size => 18, x => 5, y => 18,
- color => "#FFF", font => $f2, aa => 1),
- "draw text with non-def but 2 aa level");
- is_image($imbase, $imaa2, "check images match");
- }
-
- { # error handling check
- my $im = Imager->new(xsize => 100, ysize => 20);
- my $fnum = Imager::Font->new(file => $deffont, type => "t1");
- ok(!$im->string(font => $fnum, string => "text", size => -10),
- "set invalid size");
- is($im->errstr, "i_t1_text(): T1_AASetString failed: Invalid Argument in Function Call",
- "check error message");
- }
}
#malloc_state();
+++ /dev/null
-Imager::Font::T1xs T_PTROBJ
-Imager-File-TIFF 0.85
-=====================
-
- - for libtiff versions that support extended warning handlers (3.8.0
- or later), use them to avoid some global variables.
-
Imager-File-TIFF 0.83
=====================
use vars qw($VERSION @ISA);
BEGIN {
- $VERSION = "0.84";
+ $VERSION = "0.83";
require XSLoader;
XSLoader::load('Imager::File::TIFF', $VERSION);
BOOT:
PERL_INITIALIZE_IMAGER_CALLBACKS;
- i_tiff_init();
\ No newline at end of file
static const int text_tag_count =
sizeof(text_tag_names) / sizeof(*text_tag_names);
-#if TIFFLIB_VERSION >= 20051230
-#define USE_EXT_WARN_HANDLER
-#endif
-
-#define TIFFIO_MAGIC 0xC6A340CC
-
static void error_handler(char const *module, char const *fmt, va_list ap) {
mm_log((1, "tiff error fmt %s\n", fmt));
i_push_errorvf(0, fmt, ap);
}
-typedef struct {
- unsigned magic;
- io_glue *ig;
-#ifdef USE_EXT_WARN_HANDLER
- char *warn_buffer;
- size_t warn_size;
-#endif
-} tiffio_context_t;
-
-static void
-tiffio_context_init(tiffio_context_t *c, io_glue *ig);
-static void
-tiffio_context_final(tiffio_context_t *c);
-
#define WARN_BUFFER_LIMIT 10000
-
-#ifdef USE_EXT_WARN_HANDLER
-
-static void
-warn_handler_ex(thandle_t h, const char *module, const char *fmt, va_list ap) {
- tiffio_context_t *c = (tiffio_context_t *)h;
- char buf[200];
-
- if (c->magic != TIFFIO_MAGIC)
- return;
-
- buf[0] = '\0';
-#ifdef IMAGER_VSNPRINTF
- vsnprintf(buf, sizeof(buf), fmt, ap);
-#else
- vsprintf(buf, fmt, ap);
-#endif
- mm_log((1, "tiff warning %s\n", buf));
-
- if (!c->warn_buffer || strlen(c->warn_buffer)+strlen(buf)+2 > c->warn_size) {
- size_t new_size = c->warn_size + strlen(buf) + 2;
- char *old_buffer = c->warn_buffer;
- if (new_size > WARN_BUFFER_LIMIT) {
- new_size = WARN_BUFFER_LIMIT;
- }
- c->warn_buffer = myrealloc(c->warn_buffer, new_size);
- if (!old_buffer) c->warn_buffer[0] = '\0';
- c->warn_size = new_size;
- }
- if (strlen(c->warn_buffer)+strlen(buf)+2 <= c->warn_size) {
- strcat(c->warn_buffer, buf);
- strcat(c->warn_buffer, "\n");
- }
-}
-
-#else
-
static char *warn_buffer = NULL;
static int warn_buffer_size = 0;
}
}
-#endif
-
-static i_mutex_t mutex;
-
-void
-i_tiff_init(void) {
- mutex = i_mutex_new();
-}
-
static int save_tiff_tags(TIFF *tif, i_img *im);
static void
static
toff_t
comp_seek(thandle_t h, toff_t o, int w) {
- io_glue *ig = ((tiffio_context_t *)h)->ig;
+ io_glue *ig = (io_glue*)h;
return (toff_t) i_io_seek(ig, o, w);
}
static tsize_t
comp_read(thandle_t h, tdata_t p, tsize_t size) {
- return i_io_read(((tiffio_context_t *)h)->ig, p, size);
+ return i_io_read((io_glue *)h, p, size);
}
static tsize_t
comp_write(thandle_t h, tdata_t p, tsize_t size) {
- return i_io_write(((tiffio_context_t *)h)->ig, p, size);
+ return i_io_write((io_glue *)h, p, size);
}
static int
comp_close(thandle_t h) {
- return i_io_close(((tiffio_context_t *)h)->ig);
+ return i_io_close((io_glue *)h);
}
static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
}
i_tags_set(&im->tags, "i_format", "tiff", 4);
-#ifdef USE_EXT_WARN_HANDLER
- {
- tiffio_context_t *ctx = TIFFClientdata(tif);
- if (ctx->warn_buffer && ctx->warn_buffer[0]) {
- i_tags_set(&im->tags, "i_warning", ctx->warn_buffer, -1);
- ctx->warn_buffer[0] = '\0';
- }
- }
-#else
if (warn_buffer && *warn_buffer) {
i_tags_set(&im->tags, "i_warning", warn_buffer, -1);
*warn_buffer = '\0';
}
-#endif
for (i = 0; i < compress_value_count; ++i) {
if (compress_values[i].tag == compress) {
TIFF* tif;
TIFFErrorHandler old_handler;
TIFFErrorHandler old_warn_handler;
-#ifdef USE_EXT_WARN_HANDLER
- TIFFErrorHandlerExt old_ext_warn_handler;
-#endif
i_img *im;
int current_page;
- tiffio_context_t ctx;
-
- i_mutex_lock(mutex);
i_clear_error();
old_handler = TIFFSetErrorHandler(error_handler);
-#ifdef USE_EXT_WARN_HANDLER
- old_warn_handler = TIFFSetWarningHandler(NULL);
- old_ext_warn_handler = TIFFSetWarningHandlerExt(warn_handler_ex);
-#else
old_warn_handler = TIFFSetWarningHandler(warn_handler);
if (warn_buffer)
*warn_buffer = '\0';
-#endif
/* Add code to get the filename info from the iolayer */
/* Also add code to check for mmapped code */
mm_log((1, "i_readtiff_wiol(ig %p, allow_incomplete %d, page %d)\n", ig, allow_incomplete, page));
- tiffio_context_init(&ctx, ig);
tif = TIFFClientOpen("(Iolayer)",
"rm",
- (thandle_t) &ctx,
+ (thandle_t) ig,
comp_read,
comp_write,
comp_seek,
i_push_error(0, "Error opening file");
TIFFSetErrorHandler(old_handler);
TIFFSetWarningHandler(old_warn_handler);
-#ifdef USE_EXT_WARN_HANDLER
- TIFFSetWarningHandlerExt(old_ext_warn_handler);
-#endif
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return NULL;
}
i_push_errorf(0, "could not switch to page %d", page);
TIFFSetErrorHandler(old_handler);
TIFFSetWarningHandler(old_warn_handler);
-#ifdef USE_EXT_WARN_HANDLER
- TIFFSetWarningHandlerExt(old_ext_warn_handler);
-#endif
TIFFClose(tif);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return NULL;
}
}
if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
TIFFSetErrorHandler(old_handler);
TIFFSetWarningHandler(old_warn_handler);
-#ifdef USE_EXT_WARN_HANDLER
- TIFFSetWarningHandlerExt(old_ext_warn_handler);
-#endif
TIFFClose(tif);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
-
return im;
}
TIFF* tif;
TIFFErrorHandler old_handler;
TIFFErrorHandler old_warn_handler;
-#ifdef USE_EXT_WARN_HANDLER
- TIFFErrorHandlerExt old_ext_warn_handler;
-#endif
i_img **results = NULL;
int result_alloc = 0;
- tiffio_context_t ctx;
-
- i_mutex_lock(mutex);
i_clear_error();
old_handler = TIFFSetErrorHandler(error_handler);
-#ifdef USE_EXT_WARN_HANDLER
- old_warn_handler = TIFFSetWarningHandler(NULL);
- old_ext_warn_handler = TIFFSetWarningHandlerExt(warn_handler_ex);
-#else
old_warn_handler = TIFFSetWarningHandler(warn_handler);
if (warn_buffer)
*warn_buffer = '\0';
-#endif
-
- tiffio_context_init(&ctx, ig);
/* Add code to get the filename info from the iolayer */
/* Also add code to check for mmapped code */
tif = TIFFClientOpen("(Iolayer)",
"rm",
- (thandle_t) &ctx,
+ (thandle_t) ig,
comp_read,
comp_write,
comp_seek,
i_push_error(0, "Error opening file");
TIFFSetErrorHandler(old_handler);
TIFFSetWarningHandler(old_warn_handler);
-#ifdef USE_EXT_WARN_HANDLER
- TIFFSetWarningHandlerExt(old_ext_warn_handler);
-#endif
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return NULL;
}
TIFFSetWarningHandler(old_warn_handler);
TIFFSetErrorHandler(old_handler);
-#ifdef USE_EXT_WARN_HANDLER
- TIFFSetWarningHandlerExt(old_ext_warn_handler);
-#endif
TIFFClose(tif);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
-
return results;
}
TIFF* tif;
TIFFErrorHandler old_handler;
int i;
- tiffio_context_t ctx;
-
- i_mutex_lock(mutex);
old_handler = TIFFSetErrorHandler(error_handler);
mm_log((1, "i_writetiff_multi_wiol(ig %p, imgs %p, count %d)\n",
ig, imgs, count));
- tiffio_context_init(&ctx, ig);
+ /* FIXME: Enable the mmap interface */
tif = TIFFClientOpen("No name",
"wm",
- (thandle_t) &ctx,
+ (thandle_t) ig,
comp_read,
comp_write,
comp_seek,
mm_log((1, "i_writetiff_multi_wiol: Unable to open tif file for writing\n"));
i_push_error(0, "Could not create TIFF object");
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return 0;
}
if (!i_writetiff_low(tif, imgs[i])) {
TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return 0;
}
i_push_error(0, "Cannot write TIFF directory");
TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return 0;
}
}
TIFFSetErrorHandler(old_handler);
(void) TIFFClose(tif);
- tiffio_context_final(&ctx);
-
- i_mutex_unlock(mutex);
if (i_io_close(ig))
return 0;
TIFF* tif;
int i;
TIFFErrorHandler old_handler;
- tiffio_context_t ctx;
-
- i_mutex_lock(mutex);
old_handler = TIFFSetErrorHandler(error_handler);
mm_log((1, "i_writetiff_multi_wiol(ig %p, imgs %p, count %d)\n",
ig, imgs, count));
- tiffio_context_init(&ctx, ig);
+ /* FIXME: Enable the mmap interface */
tif = TIFFClientOpen("No name",
"wm",
- (thandle_t) &ctx,
+ (thandle_t) ig,
comp_read,
comp_write,
comp_seek,
mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
i_push_error(0, "Could not create TIFF object");
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return 0;
}
if (!i_writetiff_low_faxable(tif, imgs[i], fine)) {
TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return 0;
}
i_push_error(0, "Cannot write TIFF directory");
TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return 0;
}
}
(void) TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
-
- i_mutex_unlock(mutex);
if (i_io_close(ig))
return 0;
i_writetiff_wiol(i_img *img, io_glue *ig) {
TIFF* tif;
TIFFErrorHandler old_handler;
- tiffio_context_t ctx;
-
- i_mutex_lock(mutex);
old_handler = TIFFSetErrorHandler(error_handler);
i_clear_error();
mm_log((1, "i_writetiff_wiol(img %p, ig %p)\n", img, ig));
- tiffio_context_init(&ctx, ig);
+ /* FIXME: Enable the mmap interface */
tif = TIFFClientOpen("No name",
"wm",
- (thandle_t) &ctx,
+ (thandle_t) ig,
comp_read,
comp_write,
comp_seek,
if (!tif) {
mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
i_push_error(0, "Could not create TIFF object");
- tiffio_context_final(&ctx);
TIFFSetErrorHandler(old_handler);
- i_mutex_unlock(mutex);
return 0;
}
if (!i_writetiff_low(tif, img)) {
TIFFClose(tif);
- tiffio_context_final(&ctx);
TIFFSetErrorHandler(old_handler);
- i_mutex_unlock(mutex);
return 0;
}
(void) TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
if (i_io_close(ig))
return 0;
i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
TIFF* tif;
TIFFErrorHandler old_handler;
- tiffio_context_t ctx;
-
- i_mutex_lock(mutex);
old_handler = TIFFSetErrorHandler(error_handler);
i_clear_error();
mm_log((1, "i_writetiff_wiol(img %p, ig %p)\n", im, ig));
- tiffio_context_init(&ctx, ig);
+ /* FIXME: Enable the mmap interface */
tif = TIFFClientOpen("No name",
"wm",
- (thandle_t) &ctx,
+ (thandle_t) ig,
comp_read,
comp_write,
comp_seek,
mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
i_push_error(0, "Could not create TIFF object");
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return 0;
}
if (!i_writetiff_low_faxable(tif, im, fine)) {
TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
return 0;
}
(void) TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
- tiffio_context_final(&ctx);
- i_mutex_unlock(mutex);
if (i_io_close(ig))
return 0;
}
}
}
-
+
return 1;
}
return TIFFIsCODECConfigured(scheme);
}
-static void
-tiffio_context_init(tiffio_context_t *c, io_glue *ig) {
- c->magic = TIFFIO_MAGIC;
- c->ig = ig;
-#ifdef USE_EXT_WARN_HANDLER
- c->warn_buffer = NULL;
- c->warn_size = 0;
-#endif
-}
-
-static void
-tiffio_context_final(tiffio_context_t *c) {
- c->magic = TIFFIO_MAGIC;
-#ifdef USE_EXT_WARN_HANDLER
- if (c->warn_buffer)
- myfree(c->warn_buffer);
-#endif
-}
-
/*
=back
#include "imdatatypes.h"
-void i_tiff_init(void);
i_img * i_readtiff_wiol(io_glue *ig, int allow_incomplete, int page);
i_img ** i_readtiff_multi_wiol(io_glue *ig, int *count);
undef_int i_writetiff_wiol(i_img *im, io_glue *ig);
=head1 SEE ALSO
-Imager, Imager::API, Imager::ExtUtils, Imager::Inline
+Imager, Imager::ExtUtils, Imager::Inline
=cut
EOS
sub make_func_list {
- my @funcs = qw(i_img i_color i_fcolor i_fill_t mm_log mm_log i_img_color_channels i_img_has_alpha i_img_dim i_DF i_DFc i_DFp i_DFcp i_psamp_bits i_gsamp_bits i_psamp i_psampf);
+ my @funcs = qw(i_img i_color i_fcolor i_fill_t mm_log i_img_color_channels i_img_has_alpha i_img_dim i_DF i_DFc i_DFp i_DFcp i_psamp_bits i_gsamp_bits i_psamp i_psampf);
open FUNCS, "< imexttypes.h"
or die "Cannot open imexttypes.h: $!\n";
my $in_struct;
while (<FUNCS>) {
/^typedef struct/ && ++$in_struct;
- if ($in_struct && /\(\*f_(i[om]?_\w+)/) {
+ if ($in_struct && /\(\*f_(io?_\w+)/) {
my $name = $1;
$name =~ s/_imp$//;
push @funcs, $name;
+++ /dev/null
-#!perl -w
-use strict;
-use threads;
-use Imager;
-
-++$|;
-Imager->preload;
-
-my @tests =
- (
- [ "bench/largish.tif", "" ],
- [ "TIFF/testimg/grey16.tif", "" ],
- [ "TIFF/testimg/comp4bad.tif", "(Iolayer): Read error at scanline 120; got 0 bytes, expected 32" ],
- );
-
-my @threads;
-my $name = "A";
-for my $test (@tests) {
- push @threads,
- threads->create
- (
- sub {
- my ($file, $result, $name) = @_;
- for (1 .. 100000) {
- print $name;
- my $im = Imager->new(file => $file);
- if ($result) {
- $im and die "Expected error from $file, got image";
- Imager->errstr eq $result
- or die "Expected error '$result', got '",Imager->errstr, "'"
- }
- else {
- $im or die "Expected image got error '", Imager->errstr, "'";
- }
- }
- return;
- },
- @$test,
- $name
- );
- ++$name;
-}
-
-for my $t (@threads) {
- $t->join();
-}
-#define IMAGER_NO_CONTEXT
#include <stdarg.h>
#include "imageri.h"
*/
int
i_writebmp_wiol(i_img *im, io_glue *ig) {
- dIMCTXim(im);
i_clear_error();
/* pick a format */
i_packed_t xsize, ysize, planes, bit_count, compression, size_image, xres, yres;
i_packed_t clr_used, clr_important, offbits;
i_img *im;
- dIMCTXio(ig);
- im_log((aIMCTX, 1, "i_readbmp_wiol(ig %p)\n", ig));
+ mm_log((1, "i_readbmp_wiol(ig %p)\n", ig));
i_clear_error();
return 0;
}
- im_log((aIMCTX, 1, " bmp header: filesize %d offbits %d xsize %d ysize %d planes %d "
+ mm_log((1, " bmp header: filesize %d offbits %d xsize %d ysize %d planes %d "
"bit_count %d compression %d size %d xres %d yres %d clr_used %d "
"clr_important %d\n", (int)filesize, (int)offbits, (int)xsize,
(int)ysize, (int)planes, (int)bit_count, (int)compression,
(int)clr_important));
if (!i_int_check_image_file_limits(xsize, abs(ysize), 3, sizeof(i_sample_t))) {
- im_log((aIMCTX, 1, "i_readbmp_wiol: image size exceeds limits\n"));
+ mm_log((1, "i_readbmp_wiol: image size exceeds limits\n"));
return NULL;
}
break;
default:
- im_push_errorf(aIMCTX, 0, "unknown bit count for BMP file (%d)", (int)bit_count);
+ i_push_errorf(0, "unknown bit count for BMP file (%d)", (int)bit_count);
return NULL;
}
break;
default:
- {
- dIMCTXio(ig);
- im_fatal(aIMCTX, 1, "Unknown read_packed format code 0x%02x", code);
- }
+ i_fatal(1, "Unknown read_packed format code 0x%02x", code);
}
}
return 1;
break;
default:
- {
- dIMCTXio(ig);
- im_fatal(aIMCTX, 1, "Unknown write_packed format code 0x%02x", *format);
- }
+ i_fatal(1, "Unknown write_packed format code 0x%02x", *format);
}
++format;
}
int got_xres, got_yres, aspect_only;
int colors_used = 0;
int offset = FILEHEAD_SIZE + INFOHEAD_SIZE;
- dIMCTXim(im);
if (im->xsize > SIGNMAX32 || im->ysize > SIGNMAX32) {
i_push_error(0, "image too large to write to BMP");
int line_size = (im->xsize+7) / 8;
int x, y;
int unpacked_size;
- dIMCTXim(im);
/* round up to nearest multiple of four */
line_size = (line_size + 3) / 4 * 4;
int line_size = (im->xsize+1) / 2;
int x, y;
int unpacked_size;
- dIMCTXim(im);
/* round up to nearest multiple of four */
line_size = (line_size + 3) / 4 * 4;
int line_size = im->xsize;
int y;
int unpacked_size;
- dIMCTXim(im);
/* round up to nearest multiple of four */
line_size = (line_size + 3) / 4 * 4;
int y;
int line_size = 3 * im->xsize;
i_color bg;
- dIMCTXim(im);
i_get_file_background(im, &bg);
int i;
i_packed_t r, g, b, x;
i_color c;
- dIMCTXio(ig);
for (i = 0; i < count; ++i) {
if (!read_packed(ig, "CCCC", &b, &g, &r, &x)) {
int bit;
unsigned char *in;
long base_offset;
- dIMCTXio(ig);
if (compression != BI_RGB) {
- im_push_errorf(aIMCTX, 0, "unknown 1-bit BMP compression (%d)", compression);
+ i_push_errorf(0, "unknown 1-bit BMP compression (%d)", compression);
return NULL;
}
if (!clr_used)
clr_used = 2;
if (clr_used < 0 || clr_used > 2) {
- im_push_errorf(aIMCTX, 0, "out of range colors used (%d)", clr_used);
+ i_push_errorf(0, "out of range colors used (%d)", clr_used);
return NULL;
}
base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
if (offbits < base_offset) {
- im_push_errorf(aIMCTX, 0, "image data offset too small (%ld)", offbits);
+ i_push_errorf(0, "image data offset too small (%ld)", offbits);
return NULL;
}
int size, i;
long base_offset;
int starty;
- dIMCTXio(ig);
/* line_size is going to be smaller than xsize in most cases (and
when it's not, xsize is itself small), and hence not overflow */
clr_used = 16;
if (clr_used > 16 || clr_used < 0) {
- im_push_errorf(aIMCTX, 0, "out of range colors used (%d)", clr_used);
+ i_push_errorf(0, "out of range colors used (%d)", clr_used);
return NULL;
}
base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
if (offbits < base_offset) {
- im_push_errorf(aIMCTX, 0, "image data offset too small (%ld)", offbits);
+ i_push_errorf(0, "image data offset too small (%ld)", offbits);
return NULL;
}
myfree(packed);
myfree(line);
i_push_error(0, "invalid data during decompression");
- im_log((aIMCTX, 1, "read 4-bit: scanline overflow x %d + count %d vs xlimit %d (y %d)\n",
+ mm_log((1, "read 4-bit: scanline overflow x %d + count %d vs xlimit %d (y %d)\n",
(int)x, count, (int)xlimit, (int)y));
i_img_destroy(im);
return NULL;
myfree(packed);
myfree(line);
i_push_error(0, "invalid data during decompression");
- im_log((aIMCTX, 1, "read 4-bit: scanline overflow (unpacked) x %d + count %d vs xlimit %d (y %d)\n",
+ mm_log((1, "read 4-bit: scanline overflow (unpacked) x %d + count %d vs xlimit %d (y %d)\n",
(int)x, count, (int)xlimit, (int)y));
i_img_destroy(im);
return NULL;
else { /*if (compression == BI_RLE4) {*/
myfree(packed);
myfree(line);
- im_push_errorf(aIMCTX, 0, "unknown 4-bit BMP compression (%d)", compression);
+ i_push_errorf(0, "unknown 4-bit BMP compression (%d)", compression);
i_img_destroy(im);
return NULL;
}
i_palidx *line;
int line_size = xsize;
long base_offset;
- dIMCTXio(ig);
line_size = (line_size+3) / 4 * 4;
if (line_size < xsize) { /* if it overflowed (unlikely, but check) */
if (!clr_used)
clr_used = 256;
if (clr_used > 256 || clr_used < 0) {
- im_push_errorf(aIMCTX, 0, "out of range colors used (%d)", clr_used);
+ i_push_errorf(0, "out of range colors used (%d)", clr_used);
return NULL;
}
base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE + clr_used * 4;
if (offbits < base_offset) {
- im_push_errorf(aIMCTX, 0, "image data offset too small (%ld)", offbits);
+ i_push_errorf(0, "image data offset too small (%ld)", offbits);
return NULL;
}
}
else {
myfree(line);
- im_push_errorf(aIMCTX, 0, "unknown 8-bit BMP compression (%d)", compression);
+ i_push_errorf(0, "unknown 8-bit BMP compression (%d)", compression);
i_img_destroy(im);
return NULL;
}
const char *compression_name;
int bytes;
long base_offset = FILEHEAD_SIZE + INFOHEAD_SIZE;
- dIMCTXio(ig);
unpack_code[0] = *("v3V"+pix_size-2);
unpack_code[1] = '\0';
return 0;
}
if (rmask == 0) {
- im_push_errorf(aIMCTX, 0, "Zero mask for channel %d", i);
+ i_push_errorf(0, "Zero mask for channel %d", i);
return NULL;
}
masks.masks[i] = rmask;
base_offset += 3 * 4;
}
else {
- im_push_errorf(aIMCTX, 0, "unknown 24-bit BMP compression (%d)", compression);
+ i_push_errorf(0, "unknown 24-bit BMP compression (%d)", compression);
return NULL;
}
if (offbits < base_offset) {
- im_push_errorf(aIMCTX, 0, "image data offset too small (%ld)", offbits);
+ i_push_errorf(0, "image data offset too small (%ld)", offbits);
return NULL;
}
+++ /dev/null
-#include "imageri.h"
-#include <stdio.h>
-
-static im_slot_t slot_count;
-static im_slot_destroy_t *slot_destructors;
-static i_mutex_t slot_mutex;
-
-/*
-=item im_context_new()
-
-Create a new Imager context object.
-
-=cut
-*/
-
-im_context_t
-im_context_new(void) {
- im_context_t ctx = malloc(sizeof(im_context_struct));
- int i;
-
- if (!slot_mutex)
- slot_mutex = i_mutex_new();
-
- if (!ctx)
- return NULL;
-
- ctx->error_sp = IM_ERROR_COUNT-1;
- for (i = 0; i < IM_ERROR_COUNT; ++i) {
- ctx->error_alloc[i] = 0;
- ctx->error_stack[i].msg = NULL;
- ctx->error_stack[i].code = 0;
- }
-#ifdef IMAGER_LOG
- ctx->log_level = 0;
- ctx->lg_file = NULL;
-#endif
- ctx->max_width = 0;
- ctx->max_height = 0;
- ctx->max_bytes = DEF_BYTES_LIMIT;
-
- ctx->slot_alloc = slot_count;
- ctx->slots = calloc(sizeof(void *), ctx->slot_alloc);
- if (!ctx->slots) {
- free(ctx);
- return NULL;
- }
-
- ctx->refcount = 1;
-
-#ifdef IMAGER_TRACE_CONTEXT
- fprintf(stderr, "im_context: created %p\n", ctx);
-#endif
-
-
- return ctx;
-}
-
-/*
-=item im_context_refinc(ctx, where)
-X<im_context_refinc API>
-=section Context objects
-=synopsis im_context_refinc(aIMCTX, "a description");
-
-Add a new reference to the context.
-
-=cut
-*/
-
-void
-im_context_refinc(im_context_t ctx, const char *where) {
- ++ctx->refcount;
-
-#ifdef IMAGER_TRACE_CONTEXT
- fprintf(stderr, "im_context:%s: refinc %p (count now %lu)\n", where,
- ctx, (unsigned long)ctx->refcount);
-#endif
-}
-
-/*
-=item im_context_refdec(ctx, where)
-X<im_context_refdec API>
-=section Context objects
-=synopsis im_context_refdec(aIMCTX, "a description");
-
-Remove a reference to the context, releasing it if all references have
-been removed.
-
-=cut
-*/
-
-void
-im_context_refdec(im_context_t ctx, const char *where) {
- int i;
- im_slot_t slot;
-
- im_assert(ctx->refcount > 0);
-
- --ctx->refcount;
-
-#ifdef IMAGER_TRACE_CONTEXT
- fprintf(stderr, "im_context:%s: delete %p (count now %lu)\n", where,
- ctx, (unsigned long)ctx->refcount);
-#endif
-
- if (ctx->refcount != 0)
- return;
-
- for (slot = 0; slot < ctx->slot_alloc; ++slot) {
- if (ctx->slots[slot] && slot_destructors[slot])
- slot_destructors[slot](ctx->slots[slot]);
- }
-
- free(ctx->slots);
-
- for (i = 0; i < IM_ERROR_COUNT; ++i) {
- if (ctx->error_stack[i].msg)
- myfree(ctx->error_stack[i].msg);
- }
-#ifdef IMAGER_LOG
- if (ctx->lg_file)
- fclose(ctx->lg_file);
-#endif
-
- free(ctx);
-}
-
-/*
-=item im_context_clone(ctx)
-
-Clone an Imager context object, returning the result.
-
-=cut
-*/
-
-im_context_t
-im_context_clone(im_context_t ctx, const char *where) {
- im_context_t nctx = malloc(sizeof(im_context_struct));
- int i;
-
- if (!nctx)
- return NULL;
-
- nctx->slot_alloc = slot_count;
- nctx->slots = calloc(sizeof(void *), ctx->slot_alloc);
- if (!nctx->slots) {
- free(nctx);
- return NULL;
- }
-
- nctx->error_sp = ctx->error_sp;
- for (i = 0; i < IM_ERROR_COUNT; ++i) {
- if (ctx->error_stack[i].msg) {
- size_t sz = ctx->error_alloc[i];
- nctx->error_alloc[i] = sz;
- nctx->error_stack[i].msg = mymalloc(sz);
- memcpy(nctx->error_stack[i].msg, ctx->error_stack[i].msg, sz);
- }
- else {
- nctx->error_alloc[i] = 0;
- nctx->error_stack[i].msg = NULL;
- }
- nctx->error_stack[i].code = ctx->error_stack[i].code;
- }
-#ifdef IMAGER_LOG
- nctx->log_level = ctx->log_level;
- if (ctx->lg_file) {
- /* disable buffering, this isn't perfect */
- setvbuf(ctx->lg_file, NULL, _IONBF, 0);
-
- /* clone that and disable buffering some more */
- nctx->lg_file = fdopen(fileno(ctx->lg_file), "a");
- if (nctx->lg_file)
- setvbuf(nctx->lg_file, NULL, _IONBF, 0);
- }
- else {
- nctx->lg_file = NULL;
- }
-#endif
- nctx->max_width = ctx->max_width;
- nctx->max_height = ctx->max_height;
- nctx->max_bytes = ctx->max_bytes;
-
- nctx->refcount = 1;
-
-#ifdef IMAGER_TRACE_CONTEXT
- fprintf(stderr, "im_context:%s: cloned %p to %p\n", where, ctx, nctx);
-#endif
-
- return nctx;
-}
-
-/*
-=item im_context_slot_new(destructor, where)
-
-Allocate a new context-local-storage slot.
-
-=cut
-*/
-
-im_slot_t
-im_context_slot_new(im_slot_destroy_t destructor, const char *where) {
- im_slot_t new_slot;
- im_slot_destroy_t *new_destructors;
- if (!slot_mutex)
- slot_mutex = i_mutex_new();
-
- i_mutex_lock(slot_mutex);
-
- new_slot = slot_count++;
- new_destructors = realloc(slot_destructors, sizeof(void *) * slot_count);
- if (!new_destructors)
- i_fatal(1, "Cannot allocate memory for slot destructors");
- slot_destructors = new_destructors;
-
- slot_destructors[new_slot] = destructor;
-
-#ifdef IMAGER_TRACE_CONTEXT
- fprintf(stderr, "im_context: slot %d allocated for %s\n",
- (int)new_slot, where);
-#endif
-
- i_mutex_unlock(slot_mutex);
-
- return new_slot;
-}
-
-/*
-=item im_context_slot_set(slot, value)
-
-Set the value of a slot.
-
-Returns true on success.
-
-Aborts if the slot supplied is invalid.
-
-If reallocation of slot storage fails, returns false.
-
-=cut
-*/
-
-int
-im_context_slot_set(im_context_t ctx, im_slot_t slot, void *value) {
- if (slot < 0 || slot >= slot_count) {
- fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
- (int)slot, (int)slot_count-1);
- abort();
- }
-
- if (slot >= ctx->slot_alloc) {
- ssize_t i;
- size_t new_alloc = slot_count;
- void **new_slots = realloc(ctx->slots, sizeof(void *) * new_alloc);
-
- if (!new_slots)
- return 0;
-
- for (i = ctx->slot_alloc; i < new_alloc; ++i)
- new_slots[i] = NULL;
-
- ctx->slots = new_slots;
- ctx->slot_alloc = new_alloc;
- }
-
- ctx->slots[slot] = value;
-
-#ifdef IMAGER_TRACE_CONTEXT
- fprintf(stderr, "im_context: ctx %p slot %d set to %p\n",
- ctx, (int)slot, value);
-#endif
-
- return 1;
-}
-
-/*
-=item im_context_slot_get(ctx, slot)
-
-Retrieve the value previously stored in the given slot of the context
-object.
-
-=cut
-*/
-
-void *
-im_context_slot_get(im_context_t ctx, im_slot_t slot) {
- if (slot < 0 || slot >= slot_count) {
- fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
- (int)slot, (int)slot_count-1);
- abort();
- }
-
- if (slot >= ctx->slot_alloc)
- return NULL;
-
-#ifdef IMAGER_TRACE_CONTEXT
- fprintf(stderr, "im_context: ctx %p slot %d retrieved as %p\n",
- ctx, (int)slot, ctx->slots[slot]);
-#endif
-
- return ctx->slots[slot];
-}
-#define IMAGER_NO_CONTEXT
#include "imager.h"
#include "imageri.h"
double pc;
double res[MAXCHANNELS];
i_img *timg;
- dIMCTXim(im);
- im_log((aIMCTX,1,"i_conv(im %p, coeff %p, len %d)\n",im,coeff,len));
- im_clear_error(aIMCTX);
+ mm_log((1,"i_conv(im %p, coeff %p, len %d)\n",im,coeff,len));
+ i_clear_error();
if (len < 1) {
- im_push_error(aIMCTX, 0, "there must be at least one coefficient");
+ i_push_error(0, "there must be at least one coefficient");
return 0;
}
=cut
*/
-#define IMAGER_NO_CONTEXT
#include "imager.h"
struct chan_copy {
int i, j;
int ilimit;
i_img *im = NULL;
- dIMCTXim(src);
- im_log((aIMCTX,1,"i_convert(im %p, src %p, coeff %p,outchan %d, inchan %d)\n",
+ mm_log((1,"i_convert(im %p, src %p, coeff %p,outchan %d, inchan %d)\n",
im, src, coeff, outchan, inchan));
- im_clear_error(aIMCTX);
+ i_clear_error();
ilimit = inchan;
if (ilimit > src->channels)
ilimit = src->channels;
if (outchan > MAXCHANNELS) {
- im_push_error(aIMCTX, 0, "cannot have outchan > MAXCHANNELS");
+ i_push_error(0, "cannot have outchan > MAXCHANNELS");
return 0;
}
i_color *colors;
i_palidx *vals;
- im = im_img_pal_new(aIMCTX, src->xsize, src->ysize, outchan,
- i_maxcolors(src));
+ im = i_img_pal_new(src->xsize, src->ysize, outchan,
+ i_maxcolors(src));
/* just translate the color table */
count = i_colorcount(src);
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#define IMAGER_NO_CONTEXT
#include "imager.h"
/*
}
}
/* fprintf(stderr,"0x%08X\n",l->t); */
- if (llist_llink_push(l,l->t,data)) {
- dIMCTX;
- im_fatal(aIMCTX, 3, "out of memory\n");
+ if (llist_llink_push(l,l->t,data)) {
+ i_fatal(3, "out of memory\n");
}
}
-#define IMAGER_NO_CONTEXT
#include "imager.h"
#include "draw.h"
#include "log.h"
void
i_arc(i_img *im, i_img_dim x, i_img_dim y,double rad,double d1,double d2,const i_color *val) {
i_int_hlines hlines;
- dIMCTXim(im);
-
- im_log((aIMCTX,1,"i_arc(im %p,(x,y)=(" i_DFp "), rad %f, d1 %f, d2 %f, col %p)",
- im, i_DFcp(x, y), rad, d1, d2, val));
i_int_init_hlines_img(&hlines, im);
void
i_arc_cfill(i_img *im, i_img_dim x, i_img_dim y,double rad,double d1,double d2,i_fill_t *fill) {
i_int_hlines hlines;
- dIMCTXim(im);
-
- im_log((aIMCTX,1,"i_arc_cfill(im %p,(x,y)=(" i_DFp "), rad %f, d1 %f, d2 %f, fill %p)",
- im, i_DFcp(x, y), rad, d1, d2, fill));
i_int_init_hlines_img(&hlines, im);
const i_color *val) {
double *xvals, *yvals;
int count;
- dIMCTXim(im);
-
- im_log((aIMCTX,1,"i_arc_aa(im %p,(x,y)=(%f,%f), rad %f, d1 %f, d2 %f, col %p)",
- im, x, y, rad, d1, d2, val));
arc_poly(&count, &xvals, &yvals, x, y, rad, d1, d2);
i_fill_t *fill) {
double *xvals, *yvals;
int count;
- dIMCTXim(im);
-
- im_log((aIMCTX,1,"i_arc_aa_cfill(im %p,(x,y)=(%f,%f), rad %f, d1 %f, d2 %f, fill %p)",
- im, x, y, rad, d1, d2, fill));
arc_poly(&count, &xvals, &yvals, x, y, rad, d1, d2);
static
void
-make_minmax_list(pIMCTX, i_mmarray *dot, double x, double y, double radius) {
+make_minmax_list(i_mmarray *dot, double x, double y, double radius) {
float angle = 0.0;
float astep = radius>0.1 ? .5/radius : 10;
frac cx, cy, lx, ly, sx, sy;
- im_log((aIMCTX, 1, "make_minmax_list(dot %p, x %.2f, y %.2f, radius %.2f)\n", dot, x, y, radius));
+ mm_log((1, "make_minmax_list(dot %p, x %.2f, y %.2f, radius %.2f)\n", dot, x, y, radius));
polar_to_plane(x, y, angle, radius, &sx, &sy);
i_mmarray dot;
i_color temp;
i_img_dim ly;
- dIMCTXim(im);
- im_log((aIMCTX, 1, "i_circle_aa(im %p, centre(" i_DFp "), rad %.2f, val %p)\n",
+ mm_log((1, "i_circle_aa(im %p, centre(" i_DFp "), rad %.2f, val %p)\n",
im, i_DFcp(x, y), rad, val));
i_mmarray_cr(&dot,16*im->ysize);
- make_minmax_list(aIMCTX, &dot, x, y, rad);
+ make_minmax_list(&dot, x, y, rad);
for(ly = 0; ly<im->ysize; ly++) {
int ix, cy, minx = INT_MAX, maxx = INT_MIN;
i_img_dim x, y;
i_img_dim dx, dy;
int error;
- dIMCTXim(im);
- im_log((aIMCTX, 1, "i_circle_out(im %p, centre(" i_DFp "), rad %" i_DF ", col %p)\n",
- im, i_DFcp(xc, yc), i_DFc(r), col));
-
- im_clear_error(aIMCTX);
+ i_clear_error();
if (r < 0) {
- im_push_error(aIMCTX, 0, "circle: radius must be non-negative");
+ i_push_error(0, "circle: radius must be non-negative");
return 0;
}
i_img_dim seg2 = scale * 4;
i_img_dim seg3 = scale * 6;
i_img_dim seg4 = scale * 8;
- dIMCTXim(im);
-
- im_log((aIMCTX,1,"i_arc_out(im %p,centre(" i_DFp "), rad %" i_DF ", d1 %f, d2 %f, col %p)",
- im, i_DFcp(xc, yc), i_DFc(r), d1, d2, col));
- im_clear_error(aIMCTX);
+ i_clear_error();
if (r <= 0) {
- im_push_error(aIMCTX, 0, "arc: radius must be non-negative");
+ i_push_error(0, "arc: radius must be non-negative");
return 0;
}
if (d1 + 360 <= d2)
double t;
i_color workc = *col;
int orig_alpha = col->channel[3];
- dIMCTXim(im);
-
- im_log((aIMCTX,1,"i_circle_out_aa(im %p,centre(" i_DFp "), rad %" i_DF ", col %p)",
- im, i_DFcp(xc, yc), i_DFc(r), col));
- im_clear_error(aIMCTX);
+ i_clear_error();
if (r <= 0) {
- im_push_error(aIMCTX, 0, "arc: radius must be non-negative");
+ i_push_error(0, "arc: radius must be non-negative");
return 0;
}
i = r;
i_img_dim seg2 = scale * 4;
i_img_dim seg3 = scale * 6;
i_img_dim seg4 = scale * 8;
- dIMCTXim(im);
- im_log((aIMCTX,1,"i_arc_out_aa(im %p,centre(" i_DFp "), rad %" i_DF ", d1 %f, d2 %f, col %p)",
- im, i_DFcp(xc, yc), i_DFc(r), d1, d2, col));
-
- im_clear_error(aIMCTX);
+ i_clear_error();
if (r <= 0) {
- im_push_error(aIMCTX, 0, "arc: radius must be non-negative");
+ i_push_error(0, "arc: radius must be non-negative");
return 0;
}
if (d1 + 360 <= d2)
void
i_box(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val) {
i_img_dim x,y;
- dIMCTXim(im);
-
- im_log((aIMCTX, 1,"i_box(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n",
+ mm_log((1,"i_box(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n",
im, i_DFcp(x1,y1), i_DFcp(x2,y2), val));
for(x=x1;x<x2+1;x++) {
i_ppix(im,x,y1,val);
i_box_filled(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2, const i_color *val) {
i_img_dim x, y, width;
i_palidx index;
- dIMCTXim(im);
- im_log((aIMCTX,1,"i_box_filled(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n",
+ mm_log((1,"i_box_filled(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n",
im, i_DFcp(x1, y1), i_DFcp(x2,y2) ,val));
if (x1 > x2 || y1 > y2
int
i_box_filledf(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2, const i_fcolor *val) {
i_img_dim x, y, width;
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_box_filledf(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n",
+ mm_log((1,"i_box_filledf(im* %p, p1(" i_DFp "), p2(" i_DFp "),val %p)\n",
im, i_DFcp(x1, y1), i_DFcp(x2, y2), val));
if (x1 > x2 || y1 > y2
void
i_box_cfill(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_fill_t *fill) {
i_render r;
- dIMCTXim(im);
- im_log((aIMCTX,1,"i_box_cfill(im* %p, p1(" i_DFp "), p2(" i_DFp "), fill %p)\n",
+ mm_log((1,"i_box_cfill(im* %p, p1(" i_DFp "), p2(" i_DFp "), fill %p)\n",
im, i_DFcp(x1, y1), i_DFcp(x2,y2), fill));
++x2;
struct i_bitmap *btm;
i_img_dim x, y;
i_color val;
- dIMCTXim(im);
-
- im_log((aIMCTX, 1, "i_flood_fill(im %p, seed(" i_DFp "), col %p)",
- im, i_DFcp(seedx, seedy), dcol));
- im_clear_error(aIMCTX);
+ i_clear_error();
if (seedx < 0 || seedx >= im->xsize ||
seedy < 0 || seedy >= im->ysize) {
- im_push_error(aIMCTX, 0, "i_flood_cfill: Seed pixel outside of image");
+ i_push_error(0, "i_flood_cfill: Seed pixel outside of image");
return 0;
}
i_img_dim bxmin, bxmax, bymin, bymax;
struct i_bitmap *btm;
i_color val;
- dIMCTXim(im);
- im_log((aIMCTX, 1, "i_flood_cfill(im %p, seed(" i_DFp "), fill %p)",
- im, i_DFcp(seedx, seedy), fill));
-
- im_clear_error(aIMCTX);
+ i_clear_error();
if (seedx < 0 || seedx >= im->xsize ||
seedy < 0 || seedy >= im->ysize) {
- im_push_error(aIMCTX, 0, "i_flood_cfill: Seed pixel outside of image");
+ i_push_error(0, "i_flood_cfill: Seed pixel outside of image");
return 0;
}
i_img_dim bxmin, bxmax, bymin, bymax;
struct i_bitmap *btm;
i_img_dim x, y;
- dIMCTXim(im);
-
- im_log((aIMCTX, 1, "i_flood_cfill(im %p, seed(" i_DFp "), dcol %p, border %p)",
- im, i_DFcp(seedx, seedy), dcol, border));
- im_clear_error(aIMCTX);
+ i_clear_error();
if (seedx < 0 || seedx >= im->xsize ||
seedy < 0 || seedy >= im->ysize) {
- im_push_error(aIMCTX, 0, "i_flood_cfill: Seed pixel outside of image");
+ i_push_error(0, "i_flood_cfill: Seed pixel outside of image");
return 0;
}
const i_color *border) {
i_img_dim bxmin, bxmax, bymin, bymax;
struct i_bitmap *btm;
- dIMCTXim(im);
-
- im_log((aIMCTX, 1, "i_flood_cfill_border(im %p, seed(" i_DFp "), fill %p, border %p)",
- im, i_DFcp(seedx, seedy), fill, border));
- im_clear_error(aIMCTX);
+ i_clear_error();
if (seedx < 0 || seedx >= im->xsize ||
seedy < 0 || seedy >= im->ysize) {
- im_push_error(aIMCTX, 0, "i_flood_cfill_border: Seed pixel outside of image");
+ i_push_error(0, "i_flood_cfill_border: Seed pixel outside of image");
return 0;
}
typedef void *minthandle_t;
#endif
-#include "ext.h"
+#include "plug.h"
struct DSO_handle_tag {
minthandle_t handle;
/* #include "XSUB.h" so we can compile on threaded perls */
#include "imageri.h"
-static im_context_t
-do_get_context(void) {
- return im_get_context();
-}
-
static symbol_table_t symbol_table=
{
i_has_format,
ICL_set_internal,
ICL_info,
- do_get_context,
- im_img_empty_ch,
+ i_img_new,
+ i_img_empty,
+ i_img_empty_ch,
i_img_exorcise,
i_img_info,
i_img_setmask,
=cut
*/
-#include "imageri.h"
+#include "imager.h"
#include <stdio.h>
#include <stdlib.h>
+/* we never actually use the last item - it's the NULL terminator */
+#define ERRSTK 20
+static i_errmsg error_stack[ERRSTK];
+static int error_sp = ERRSTK - 1;
+/* we track the amount of space used each string, so we don't reallocate
+ space unless we need to.
+ This also means that a memory tracking library may see the memory
+ allocated for this as a leak. */
+static int error_space[ERRSTK];
+
+static i_error_cb error_cb;
+static i_failed_cb failed_cb;
+static int failures_fatal;
+static char *argv0;
+
+/*
+=item i_set_argv0(char const *program)
+
+Sets the name of the program to be displayed in fatal error messages.
+
+The simplest way to use this is just:
+
+ i_set_argv0(argv[0]);
+
+when your program starts.
+*/
+void i_set_argv0(char const *name) {
+ char *dupl;
+ if (!name)
+ return;
+ /* if the user has an existing string of MAXINT length then
+ the system is broken anyway */
+ dupl = mymalloc(strlen(name)+1); /* check 17jul05 tonyc */
+ strcpy(dupl, name);
+ if (argv0)
+ myfree(argv0);
+ argv0 = dupl;
+}
+
/*
-=item im_errors(ctx)
-=synopsis i_errmsg *errors = im_errors(aIMCTX);
-=synopsis i_errmsg *errors = i_errors();
+=item i_set_failure_fatal(int failure_fatal)
+
+If failure_fatal is non-zero then any future failures will result in
+Imager exiting your program with a message describing the failure.
+
+Returns the previous setting.
+
+=cut
+*/
+int i_set_failures_fatal(int fatal) {
+ int old = failures_fatal;
+ failures_fatal = fatal;
+
+ return old;
+}
+
+/*
+=item i_set_error_cb(i_error_cb)
+
+Sets a callback function that is called each time an error is pushed
+onto the error stack.
+
+Returns the previous callback.
+
+i_set_failed_cb() is probably more useful.
+
+=cut
+*/
+i_error_cb i_set_error_cb(i_error_cb cb) {
+ i_error_cb old = error_cb;
+ error_cb = cb;
+
+ return old;
+}
+
+/*
+=item i_set_failed_cb(i_failed_cb cb)
+
+Sets a callback function that is called each time an Imager function
+fails.
+
+Returns the previous callback.
+
+=cut
+*/
+i_failed_cb i_set_failed_cb(i_failed_cb cb) {
+ i_failed_cb old = failed_cb;
+ failed_cb = cb;
+
+ return old;
+}
+
+/*
+=item i_errors()
Returns a pointer to the first element of an array of error messages,
terminated by a NULL pointer. The highest level message is first.
-Also callable as C<i_errors()>.
-
=cut
*/
-i_errmsg *im_errors(im_context_t ctx) {
- return ctx->error_stack + ctx->error_sp;
+i_errmsg *i_errors() {
+ return error_stack + error_sp;
}
/*
=over
-=item im_clear_error(ctx)
-X<im_clear_error API>X<i_clear_error API>
-=synopsis im_clear_error(aIMCTX);
+=item i_clear_error()
=synopsis i_clear_error();
=category Error handling
Called by any Imager function before doing any other processing.
-Also callable as C<i_clear_error()>.
-
=cut
*/
-
-void
-im_clear_error(im_context_t ctx) {
+void i_clear_error() {
#ifdef IMAGER_DEBUG_MALLOC
int i;
- for (i = 0; i < IM_ERROR_COUNT; ++i) {
- if (ctx->error_space[i]) {
- myfree(ctx->error_stack[i].msg);
- ctx->error_stack[i].msg = NULL;
- ctx->error_space[i] = 0;
+ for (i = 0; i < ERRSTK; ++i) {
+ if (error_space[i]) {
+ myfree(error_stack[i].msg);
+ error_stack[i].msg = NULL;
+ error_space[i] = 0;
}
}
#endif
- ctx->error_sp = IM_ERROR_COUNT-1;
+ error_sp = ERRSTK-1;
}
/*
-=item im_push_error(ctx, code, message)
-X<im_push_error API>X<i_push_error API>
+=item i_push_error(int code, char const *msg)
=synopsis i_push_error(0, "Yep, it's broken");
=synopsis i_push_error(errno, "Error writing");
-=synopsis im_push_error(aIMCTX, 0, "Something is wrong");
=category Error handling
Called by an Imager function to push an error message onto the stack.
=cut
*/
-void
-im_push_error(im_context_t ctx, int code, char const *msg) {
+void i_push_error(int code, char const *msg) {
size_t size = strlen(msg)+1;
- if (ctx->error_sp <= 0)
+ if (error_sp <= 0)
/* bad, bad programmer */
return;
- --ctx->error_sp;
- if (ctx->error_alloc[ctx->error_sp] < size) {
- if (ctx->error_stack[ctx->error_sp].msg)
- myfree(ctx->error_stack[ctx->error_sp].msg);
+ --error_sp;
+ if (error_space[error_sp] < size) {
+ if (error_stack[error_sp].msg)
+ myfree(error_stack[error_sp].msg);
/* memory allocated on the following line is only ever released when
we need a bigger string */
/* size is size (len+1) of an existing string, overflow would mean
the system is broken anyway */
- ctx->error_stack[ctx->error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */
- ctx->error_alloc[ctx->error_sp] = size;
+ error_stack[error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */
+ error_space[error_sp] = size;
}
- strcpy(ctx->error_stack[ctx->error_sp].msg, msg);
- ctx->error_stack[ctx->error_sp].code = code;
+ strcpy(error_stack[error_sp].msg, msg);
+ error_stack[error_sp].code = code;
+
+ if (error_cb)
+ error_cb(code, msg);
}
/*
-=item im_push_errorvf(ctx, code, format, args)
-X<im_push_error_vf API>X<i_push_errorvf API>
-=synopsis va_args args;
-=synopsis va_start(args, lastarg);
-=synopsis im_push_errorvf(ctx, code, format, args);
+=item i_push_errorvf(int C<code>, char const *C<fmt>, va_list C<ap>)
+
=category Error handling
Intended for use by higher level functions, takes a varargs pointer
Does not support perl specific format codes.
-Also callable as C<i_push_errorvf(code, format, args)>
-
=cut
*/
-void
-im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list ap) {
+void i_push_errorvf(int code, char const *fmt, va_list ap) {
char buf[1024];
#if defined(IMAGER_VSNPRINTF)
vsnprintf(buf, sizeof(buf), fmt, ap);
*/
vsprintf(buf, fmt, ap);
#endif
- im_push_error(ctx, code, buf);
+ i_push_error(code, buf);
}
/*
=cut
*/
-void
-i_push_errorf(int code, char const *fmt, ...) {
+void i_push_errorf(int code, char const *fmt, ...) {
va_list ap;
va_start(ap, fmt);
i_push_errorvf(code, fmt, ap);
va_end(ap);
}
-/*
-=item im_push_errorf(ctx, code, char const *fmt, ...)
-=synopsis im_push_errorf(aIMCTX, errno, "Cannot open file %s: %d", filename, errno);
-=category Error handling
-
-A version of im_push_error() that does printf() like formatting.
-
-Does not support perl specific format codes.
-
-=cut
-*/
-void
-im_push_errorf(im_context_t ctx, int code, char const *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- im_push_errorvf(ctx, code, fmt, ap);
- va_end(ap);
-}
-
#ifdef IMAGER_I_FAILED
#error "This isn't used and is untested"
im_assert_fail(char const *file, int line, char const *message) {
fprintf(stderr, "Assertion failed line %d file %s: %s\n",
line, file, message);
- abort();
+ exit(EXIT_FAILURE);
}
/*
-#include "imdatatypes.h"
+#include "imager.h"
#ifndef IMAGER_EXT_H
#define IMAGER_EXT_H
int (*getobj)(void *hv_t,char* key,char* type,void **store);
} UTIL_table_t;
-typedef struct {
- undef_int (*i_has_format)(char *frmt);
- i_color*(*ICL_set)(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a);
- void (*ICL_info)(const i_color *cl);
-
- im_context_t (*im_get_context_f)(void);
- i_img*(*im_img_empty_ch_f)(im_context_t, i_img *im,i_img_dim x,i_img_dim y,int ch);
- void(*i_img_exorcise_f)(i_img *im);
-
- void(*i_img_info_f)(i_img *im,i_img_dim *info);
-
- void(*i_img_setmask_f)(i_img *im,int ch_mask);
- int (*i_img_getmask_f)(i_img *im);
-
- /*
- int (*i_ppix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val);
- int (*i_gpix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val);
- */
- void(*i_box)(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val);
- void(*i_line)(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val,int endp);
- void(*i_arc)(i_img *im,i_img_dim x,i_img_dim y,double rad,double d1,double d2,const i_color *val);
- void(*i_copyto)(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty);
- void(*i_copyto_trans)(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty,const i_color *trans);
- int(*i_rubthru)(i_img *im,i_img *src,i_img_dim tx,i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy);
-
-} symbol_table_t;
-
#endif
-#define IMAGER_NO_CONTEXT
#include "imager.h"
#include "imageri.h"
-#define IMAGER_NO_CONTEXT
#include "imager.h"
#include "imageri.h"
#include <stdlib.h>
unsigned char ch;
unsigned int new_color;
i_color rcolor;
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_contrast(im %p, intensity %f)\n", im, intensity));
+ mm_log((1,"i_contrast(im %p, intensity %f)\n", im, intensity));
if(intensity < 0) return;
i_img_dim x, y;
int ch;
int invert_channels = all ? im->channels : i_img_color_channels(im);
- dIMCTXim(im);
- im_log((aIMCTX,1,"i_hardinvert)low(im %p, all %d)\n", im, all));
+ mm_log((1,"i_hardinvert(im %p)\n", im));
#code im->bits <= 8
IM_COLOR *row, *entry;
float damount = amount * 2;
i_color rcolor;
int color_inc = 0;
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_noise(im %p, intensity %.2f\n", im, amount));
+ mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
if(amount < 0) return;
double aX, aY, aL;
double fZ;
unsigned char px1, px2, py1, py2;
- dIMCTXim(im);
+
i_img new_im;
- im_log((aIMCTX, 1, "i_bumpmap(im %p, add_im %p, channel %d, light(" i_DFp "), st %" i_DF ")\n",
+ mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light(" i_DFp "), st %" i_DF ")\n",
im, bump, channel, i_DFcp(light_x, light_y), i_DFc(st)));
if(channel >= bump->channels) {
- im_log((aIMCTX, 1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
+ mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
return;
}
fvec R; /* Reflection vector */
fvec V; /* Vision vector */
- dIMCTXim(im);
-
- im_log((aIMCTX, 1, "i_bumpmap_complex(im %p, bump %p, channel %d, t(" i_DFp
+ mm_log((1, "i_bumpmap_complex(im %p, bump %p, channel %d, t(" i_DFp
"), Lx %.2f, Ly %.2f, Lz %.2f, cd %.2f, cs %.2f, n %.2f, Ia %p, Il %p, Is %p)\n",
im, bump, channel, i_DFcp(tx, ty), Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
if (channel >= bump->channels) {
- im_log((aIMCTX, 1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
+ mm_log((1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
return;
}
i_img_dim gsum, gmin, gmax;
i_img_dim bsum, bmin, bmax;
i_img_dim rcl, rcu, gcl, gcu, bcl, bcu;
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
+ mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
rsum=gsum=bsum=0;
for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
size_t bytes;
double *fdist;
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
+ mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
for(p = 0; p<num; p++) {
- im_log((aIMCTX,1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
+ mm_log((1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
ICL_info(&ival[p]);
}
fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
break;
default:
- im_fatal(aIMCTX, 3,"i_gradgen: Unknown distance measure\n");
+ i_fatal(3,"i_gradgen: Unknown distance measure\n");
}
cs += fdist[p];
}
i_img_dim x, y;
i_img_dim xsize = im->xsize;
i_img_dim ysize = im->ysize;
- dIMCTXim(im);
- im_log((aIMCTX,1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
+ mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
for(p = 0; p<num; p++) {
- im_log((aIMCTX, 1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
+ mm_log((1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
ICL_info(&ival[p]);
}
mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
break;
default:
- im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
+ i_fatal(3,"i_nearest_color: Unknown distance measure\n");
}
for(p = 1; p<num; p++) {
curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
break;
default:
- im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
+ i_fatal(3,"i_nearest_color: Unknown distance measure\n");
}
if (curdist < mindist) {
mindist = curdist;
i_img_dim ysize = im->ysize;
int *cmatch;
size_t ival_bytes, tval_bytes;
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
+ mm_log((1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
i_clear_error();
mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
break;
default:
- im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
+ i_fatal(3,"i_nearest_color: Unknown distance measure\n");
}
for(p = 1; p<num; p++) {
curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
break;
default:
- im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
+ i_fatal(3,"i_nearest_color: Unknown distance measure\n");
}
if (curdist < mindist) {
mindist = curdist;
i_img *out;
int outchans, diffchans;
i_img_dim xsize, ysize;
- dIMCTXim(im1);
i_clear_error();
if (im1->channels != im2->channels) {
i_fountain_seg *my_segs;
i_fill_combine_f combine_func = NULL;
i_fill_combinef_f combinef_func = NULL;
- dIMCTXim(im);
i_clear_error();
-#define IMAGER_NO_CONTEXT
#include "imager.h"
static void flip_h(i_img *im);
undef_int
i_flipxy(i_img *im, int direction) {
- dIMCTXim(im);
i_clear_error();
- im_log((aIMCTX, 1, "i_flipxy(im %p, direction %d)\n", im, direction ));
+ mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
if (!im)
return 0;
break;
default:
- im_log((aIMCTX, 1, "i_flipxy: direction is invalid\n" ));
- im_push_errorf(aIMCTX, 0, "direction %d invalid", direction);
+ mm_log((1, "i_flipxy: direction is invalid\n" ));
+ i_push_errorf(0, "direction %d invalid", direction);
return 0;
+
}
return 1;
}
--- /dev/null
+#include "imager.h"
+#include "imrender.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_LIBT1
+#endif
+
+
+/*
+=head1 NAME
+
+font.c - implements font handling functions for t1 and truetype fonts
+
+=head1 SYNOPSIS
+
+ i_init_fonts();
+
+ #ifdef HAVE_LIBT1
+ fontnum = i_t1_new(path_to_pfb, path_to_afm);
+ i_t1_bbox(fontnum, points, "foo", 3, i_img_dim cords[BOUNDING_BOX_COUNT]);
+ rc = i_t1_destroy(fontnum);
+ #endif
+
+ #ifdef HAVE_LIBTT
+ handle = i_tt_new(path_to_ttf);
+ rc = i_tt_bbox(handle, points, "foo", 3, int cords[6], utf8);
+ i_tt_destroy(handle);
+
+ // and much more
+
+=head1 DESCRIPTION
+
+font.c implements font creation, rendering, bounding box functions and
+more for Imager.
+
+=head1 FUNCTION REFERENCE
+
+Some of these functions are internal.
+
+=over
+
+=cut
+
+*/
+
+
+/* Truetype font support */
+#ifdef HAVE_LIBTT
+
+/* These are enabled by default when configuring Freetype 1.x
+ I haven't a clue how to reliably detect it at compile time.
+
+ We need a compilation probe in Makefile.PL
+*/
+#define FTXPOST 1
+#define FTXERR18 1
+
+#include <freetype.h>
+#define TT_CHC 5
+
+#ifdef FTXPOST
+#include <ftxpost.h>
+#endif
+
+#ifdef FTXERR18
+#include <ftxerr18.h>
+#endif
+
+/* some versions of FT1.x don't seem to define this - it's font defined
+ so it won't change */
+#ifndef TT_MS_LANGID_ENGLISH_GENERAL
+#define TT_MS_LANGID_ENGLISH_GENERAL 0x0409
+#endif
+
+/* convert a code point into an index in the glyph cache */
+#define TT_HASH(x) ((x) & 0xFF)
+
+typedef struct i_glyph_entry_ {
+ TT_Glyph glyph;
+ unsigned long ch;
+} i_tt_glyph_entry;
+
+#define TT_NOCHAR (~0UL)
+
+struct TT_Instancehandle_ {
+ TT_Instance instance;
+ TT_Instance_Metrics imetrics;
+ TT_Glyph_Metrics gmetrics[256];
+ i_tt_glyph_entry glyphs[256];
+ int smooth;
+ int order;
+ i_img_dim ptsize;
+};
+
+typedef struct TT_Instancehandle_ TT_Instancehandle;
+
+struct TT_Fonthandle_ {
+ TT_Face face;
+ TT_Face_Properties properties;
+ TT_Instancehandle instanceh[TT_CHC];
+ TT_CharMap char_map;
+#ifdef FTXPOST
+ int loaded_names;
+ TT_Error load_cond;
+#endif
+};
+
+/* Defines */
+
+#define USTRCT(x) ((x).z)
+#define TT_VALID( handle ) ( ( handle ).z != NULL )
+
+static void i_tt_push_error(TT_Error rc);
+
+/* Prototypes */
+
+static int i_tt_get_instance( TT_Fonthandle *handle, i_img_dim points, int smooth );
+static void i_tt_init_raster_map( TT_Raster_Map* bit, i_img_dim width, i_img_dim height, int smooth );
+static void i_tt_done_raster_map( TT_Raster_Map *bit );
+static void i_tt_clear_raster_map( TT_Raster_Map* bit );
+static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,i_img_dim x_off, i_img_dim y_off );
+static int i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j );
+static void
+i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics,
+ TT_Raster_Map *bit, TT_Raster_Map *small_bit,
+ i_img_dim x_off, i_img_dim y_off, int smooth );
+static int
+i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
+ TT_Raster_Map *small_bit, i_img_dim cords[6],
+ char const* txt, size_t len, int smooth, int utf8 );
+static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, const i_color *cl, int smooth );
+static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, int channel, int smooth );
+static int
+i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, i_img_dim cords[6],
+ double points, char const* txt, size_t len, int smooth, int utf8 );
+static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, size_t len, i_img_dim cords[6], int utf8 );
+
+
+/* static globals needed */
+
+static int TT_initialized = 0;
+static TT_Engine engine;
+static int LTT_dpi = 72; /* FIXME: this ought to be a part of the call interface */
+static int LTT_hinted = 1; /* FIXME: this too */
+
+
+/*
+ * FreeType interface
+ */
+
+
+/*
+=item init_tt()
+
+Initializes the freetype font rendering engine
+
+=cut
+*/
+
+static undef_int
+i_init_tt(void) {
+ TT_Error error;
+ TT_Byte palette[] = { 0, 64, 127, 191, 255 };
+
+ i_clear_error();
+
+ mm_log((1,"init_tt()\n"));
+ error = TT_Init_FreeType( &engine );
+ if ( error ){
+ mm_log((1,"Initialization of freetype failed, code = 0x%x\n",
+ (unsigned)error));
+ i_tt_push_error(error);
+ i_push_error(0, "Could not initialize freetype 1.x");
+ return(1);
+ }
+
+#ifdef FTXPOST
+ error = TT_Init_Post_Extension( engine );
+ if (error) {
+ mm_log((1, "Initialization of Post extension failed = 0x%x\n",
+ (unsigned)error));
+
+ i_tt_push_error(error);
+ i_push_error(0, "Could not initialize FT 1.x POST extension");
+ return 1;
+ }
+#endif
+
+ error = TT_Set_Raster_Gray_Palette(engine, palette);
+ if (error) {
+ mm_log((1, "Initialization of gray levels failed = 0x%x\n",
+ (unsigned)error));
+ i_tt_push_error(error);
+ i_push_error(0, "Could not initialize FT 1.x POST extension");
+ return 1;
+ }
+
+ TT_initialized = 1;
+
+ return(0);
+}
+
+
+/*
+=item i_tt_get_instance(handle, points, smooth)
+
+Finds a points+smooth instance or if one doesn't exist in the cache
+allocates room and returns its cache entry
+
+ fontname - path to the font to load
+ handle - handle to the font.
+ points - points of the requested font
+ smooth - boolean (True: antialias on, False: antialias is off)
+
+=cut
+*/
+
+static
+int
+i_tt_get_instance( TT_Fonthandle *handle, i_img_dim points, int smooth ) {
+ int i,idx;
+ TT_Error error;
+
+ mm_log((1,"i_tt_get_instance(handle %p, points %" i_DF ", smooth %d)\n",
+ handle, i_DFc(points), smooth));
+
+ if (smooth == -1) { /* Smooth doesn't matter for this search */
+ for(i=0;i<TT_CHC;i++) {
+ if (handle->instanceh[i].ptsize==points) {
+ mm_log((1,"i_tt_get_instance: in cache - (non selective smoothing search) returning %d\n",i));
+ return i;
+ }
+ }
+ smooth=1; /* We will be adding a font - add it as smooth then */
+ } else { /* Smooth doesn't matter for this search */
+ for(i=0;i<TT_CHC;i++) {
+ if (handle->instanceh[i].ptsize == points
+ && handle->instanceh[i].smooth == smooth) {
+ mm_log((1,"i_tt_get_instance: in cache returning %d\n",i));
+ return i;
+ }
+ }
+ }
+
+ /* Found the instance in the cache - return the cache index */
+
+ for(idx=0;idx<TT_CHC;idx++) {
+ if (!(handle->instanceh[idx].order)) break; /* find the lru item */
+ }
+
+ mm_log((1,"i_tt_get_instance: lru item is %d\n",idx));
+ mm_log((1,"i_tt_get_instance: lru pointer %p\n",
+ USTRCT(handle->instanceh[idx].instance) ));
+
+ if ( USTRCT(handle->instanceh[idx].instance) ) {
+ mm_log((1,"i_tt_get_instance: freeing lru item from cache %d\n",idx));
+
+ /* Free cached glyphs */
+ for(i=0;i<256;i++)
+ if ( USTRCT(handle->instanceh[idx].glyphs[i].glyph) )
+ TT_Done_Glyph( handle->instanceh[idx].glyphs[i].glyph );
+
+ for(i=0;i<256;i++) {
+ handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR;
+ USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL;
+ }
+
+ /* Free instance if needed */
+ TT_Done_Instance( handle->instanceh[idx].instance );
+ }
+
+ /* create and initialize instance */
+ /* FIXME: probably a memory leak on fail */
+
+ (void) (( error = TT_New_Instance( handle->face, &handle->instanceh[idx].instance ) ) ||
+ ( error = TT_Set_Instance_Resolutions( handle->instanceh[idx].instance, LTT_dpi, LTT_dpi ) ) ||
+ ( error = TT_Set_Instance_CharSize( handle->instanceh[idx].instance, points*64 ) ) );
+
+ if ( error ) {
+ mm_log((1, "Could not create and initialize instance: error %x.\n",
+ (unsigned)error ));
+ return -1;
+ }
+
+ /* Now that the instance should the inplace we need to lower all of the
+ ru counts and put `this' one with the highest entry */
+
+ for(i=0;i<TT_CHC;i++) handle->instanceh[i].order--;
+
+ handle->instanceh[idx].order=TT_CHC-1;
+ handle->instanceh[idx].ptsize=points;
+ handle->instanceh[idx].smooth=smooth;
+ TT_Get_Instance_Metrics( handle->instanceh[idx].instance, &(handle->instanceh[idx].imetrics) );
+
+ /* Zero the memory for the glyph storage so they are not thought as
+ cached if they haven't been cached since this new font was loaded */
+
+ for(i=0;i<256;i++) {
+ handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR;
+ USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL;
+ }
+
+ return idx;
+}
+
+
+/*
+=item i_tt_new(fontname)
+
+Creates a new font handle object, finds a character map and initialise the
+the font handle's cache
+
+ fontname - path to the font to load
+
+=cut
+*/
+
+TT_Fonthandle*
+i_tt_new(const char *fontname) {
+ TT_Error error;
+ TT_Fonthandle *handle;
+ unsigned short i,n;
+ unsigned short platform,encoding;
+
+ if (!TT_initialized && i_init_tt()) {
+ i_push_error(0, "Could not initialize FT1 engine");
+ return NULL;
+ }
+
+ i_clear_error();
+
+ mm_log((1,"i_tt_new(fontname '%s')\n",fontname));
+
+ /* allocate memory for the structure */
+
+ handle = mymalloc( sizeof(TT_Fonthandle) ); /* checked 5Nov05 tonyc */
+
+ /* load the typeface */
+ error = TT_Open_Face( engine, fontname, &handle->face );
+ if ( error ) {
+ if ( error == TT_Err_Could_Not_Open_File ) {
+ mm_log((1, "Could not find/open %s.\n", fontname ));
+ }
+ else {
+ mm_log((1, "Error while opening %s, error code = 0x%x.\n",fontname,
+ (unsigned)error ));
+ }
+ i_tt_push_error(error);
+ return NULL;
+ }
+
+ TT_Get_Face_Properties( handle->face, &(handle->properties) );
+
+ /* First, look for a Unicode charmap */
+ n = handle->properties.num_CharMaps;
+ USTRCT( handle->char_map )=NULL; /* Invalidate character map */
+
+ for ( i = 0; i < n; i++ ) {
+ TT_Get_CharMap_ID( handle->face, i, &platform, &encoding );
+ if ( (platform == 3 && encoding == 1 )
+ || (platform == 0 && encoding == 0 ) ) {
+ mm_log((2,"i_tt_new - found char map platform %u encoding %u\n",
+ platform, encoding));
+ TT_Get_CharMap( handle->face, i, &(handle->char_map) );
+ break;
+ }
+ }
+ if (!USTRCT(handle->char_map) && n != 0) {
+ /* just use the first one */
+ TT_Get_CharMap( handle->face, 0, &(handle->char_map));
+ }
+
+ /* Zero the pointsizes - and ordering */
+
+ for(i=0;i<TT_CHC;i++) {
+ USTRCT(handle->instanceh[i].instance)=NULL;
+ handle->instanceh[i].order=i;
+ handle->instanceh[i].ptsize=0;
+ handle->instanceh[i].smooth=-1;
+ }
+
+#ifdef FTXPOST
+ handle->loaded_names = 0;
+#endif
+
+ mm_log((1,"i_tt_new <- %p\n",handle));
+ return handle;
+}
+
+
+
+/*
+ * raster map management
+ */
+
+/*
+=item i_tt_init_raster_map(bit, width, height, smooth)
+
+Allocates internal memory for the bitmap as needed by the parameters (internal)
+
+ bit - bitmap to allocate into
+ width - width of the bitmap
+ height - height of the bitmap
+ smooth - boolean (True: antialias on, False: antialias is off)
+
+=cut
+*/
+
+static
+void
+i_tt_init_raster_map( TT_Raster_Map* bit, i_img_dim width, i_img_dim height, int smooth ) {
+
+ mm_log((1,"i_tt_init_raster_map( bit %p, width %" i_DF ", height %" i_DF
+ ", smooth %d)\n", bit, i_DFc(width), i_DFc(height), smooth));
+
+ bit->rows = height;
+ bit->width = ( width + 3 ) & -4;
+ bit->flow = TT_Flow_Down;
+
+ if ( smooth ) {
+ bit->cols = bit->width;
+ bit->size = bit->rows * bit->width;
+ } else {
+ bit->cols = ( bit->width + 7 ) / 8; /* convert to # of bytes */
+ bit->size = bit->rows * bit->cols; /* number of bytes in buffer */
+ }
+
+ /* rows can be 0 for some glyphs, for example ' ' */
+ if (bit->rows && bit->size / bit->rows != bit->cols) {
+ i_fatal(0, "Integer overflow calculating bitmap size (%d, %d)\n",
+ bit->width, bit->rows);
+ }
+
+ mm_log((1,"i_tt_init_raster_map: bit->width %d, bit->cols %d, bit->rows %d, bit->size %ld)\n", bit->width, bit->cols, bit->rows, bit->size ));
+
+ bit->bitmap = (void *) mymalloc( bit->size ); /* checked 6Nov05 tonyc */
+ if ( !bit->bitmap ) i_fatal(0,"Not enough memory to allocate bitmap (%d)!\n",bit->size );
+}
+
+
+/*
+=item i_tt_clear_raster_map(bit)
+
+Frees the bitmap data and sets pointer to NULL (internal)
+
+ bit - bitmap to free
+
+=cut
+*/
+
+static
+void
+i_tt_done_raster_map( TT_Raster_Map *bit ) {
+ myfree( bit->bitmap );
+ bit->bitmap = NULL;
+}
+
+
+/*
+=item i_tt_clear_raster_map(bit)
+
+Clears the specified bitmap (internal)
+
+ bit - bitmap to zero
+
+=cut
+*/
+
+
+static
+void
+i_tt_clear_raster_map( TT_Raster_Map* bit ) {
+ memset( bit->bitmap, 0, bit->size );
+}
+
+
+/*
+=item i_tt_blit_or(dst, src, x_off, y_off)
+
+function that blits one raster map into another (internal)
+
+ dst - destination bitmap
+ src - source bitmap
+ x_off - x offset into the destination bitmap
+ y_off - y offset into the destination bitmap
+
+=cut
+*/
+
+static
+void
+i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,i_img_dim x_off, i_img_dim y_off ) {
+ i_img_dim x, y;
+ i_img_dim x1, x2, y1, y2;
+ unsigned char *s, *d;
+
+ x1 = x_off < 0 ? -x_off : 0;
+ y1 = y_off < 0 ? -y_off : 0;
+
+ x2 = (int)dst->cols - x_off;
+ if ( x2 > src->cols ) x2 = src->cols;
+
+ y2 = (int)dst->rows - y_off;
+ if ( y2 > src->rows ) y2 = src->rows;
+
+ if ( x1 >= x2 ) return;
+
+ /* do the real work now */
+
+ for ( y = y1; y < y2; ++y ) {
+ s = ( (unsigned char*)src->bitmap ) + y * src->cols + x1;
+ d = ( (unsigned char*)dst->bitmap ) + ( y + y_off ) * dst->cols + x1 + x_off;
+
+ for ( x = x1; x < x2; ++x ) {
+ if (*s > *d)
+ *d = *s;
+ d++;
+ s++;
+ }
+ }
+}
+
+/* useful for debugging */
+#if 0
+
+static void dump_raster_map(FILE *out, TT_Raster_Map *bit ) {
+ int x, y;
+ fprintf(out, "cols %d rows %d flow %d\n", bit->cols, bit->rows, bit->flow);
+ for (y = 0; y < bit->rows; ++y) {
+ fprintf(out, "%2d:", y);
+ for (x = 0; x < bit->cols; ++x) {
+ if ((x & 7) == 0 && x) putc(' ', out);
+ fprintf(out, "%02x", ((unsigned char *)bit->bitmap)[y*bit->cols+x]);
+ }
+ putc('\n', out);
+ }
+}
+
+#endif
+
+/*
+=item i_tt_get_glyph(handle, inst, j)
+
+Function to see if a glyph exists and if so cache it (internal)
+
+ handle - pointer to font handle
+ inst - font instance
+ j - charcode of glyph
+
+=cut
+*/
+
+static
+int
+i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j) {
+ unsigned short load_flags, code;
+ TT_Error error;
+
+ mm_log((1, "i_tt_get_glyph(handle %p, inst %d, j %lu (%c))\n",
+ handle,inst,j, (int)((j >= ' ' && j <= '~') ? j : '.')));
+
+ /*mm_log((1, "handle->instanceh[inst].glyphs[j]=0x%08X\n",handle->instanceh[inst].glyphs[j] ));*/
+
+ if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)
+ && handle->instanceh[inst].glyphs[TT_HASH(j)].ch == j) {
+ mm_log((1,"i_tt_get_glyph: %lu in cache\n",j));
+ return 1;
+ }
+
+ if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph) ) {
+ /* clean up the entry */
+ TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
+ USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
+ handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR;
+ }
+
+ /* Ok - it wasn't cached - try to get it in */
+ load_flags = TTLOAD_SCALE_GLYPH;
+ if ( LTT_hinted ) load_flags |= TTLOAD_HINT_GLYPH;
+
+ if ( !TT_VALID(handle->char_map) ) {
+ code = (j - ' ' + 1) < 0 ? 0 : (j - ' ' + 1);
+ if ( code >= handle->properties.num_Glyphs ) code = 0;
+ } else code = TT_Char_Index( handle->char_map, j );
+
+ if ( (error = TT_New_Glyph( handle->face, &handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)) ) {
+ mm_log((1, "Cannot allocate and load glyph: error %#x.\n", (unsigned)error ));
+ i_push_error(error, "TT_New_Glyph()");
+ return 0;
+ }
+ if ( (error = TT_Load_Glyph( handle->instanceh[inst].instance, handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, code, load_flags)) ) {
+ mm_log((1, "Cannot allocate and load glyph: error %#x.\n", (unsigned)error ));
+ /* Don't leak */
+ TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
+ USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
+ i_push_error(error, "TT_Load_Glyph()");
+ return 0;
+ }
+
+ /* At this point the glyph should be allocated and loaded */
+ handle->instanceh[inst].glyphs[TT_HASH(j)].ch = j;
+
+ /* Next get the glyph metrics */
+ error = TT_Get_Glyph_Metrics( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph,
+ &handle->instanceh[inst].gmetrics[TT_HASH(j)] );
+ if (error) {
+ mm_log((1, "TT_Get_Glyph_Metrics: error %#x.\n", (unsigned)error ));
+ TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
+ USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
+ handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR;
+ i_push_error(error, "TT_Get_Glyph_Metrics()");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+=item i_tt_has_chars(handle, text, len, utf8, out)
+
+Check if the given characters are defined by the font. Note that len
+is the number of bytes, not the number of characters (when utf8 is
+non-zero).
+
+Returns the number of characters that were checked.
+
+=cut
+*/
+
+size_t
+i_tt_has_chars(TT_Fonthandle *handle, char const *text, size_t len, int utf8,
+ char *out) {
+ size_t count = 0;
+ mm_log((1, "i_tt_has_chars(handle %p, text %p, len %ld, utf8 %d)\n",
+ handle, text, (long)len, utf8));
+
+ while (len) {
+ unsigned long c;
+ int index;
+ if (utf8) {
+ c = i_utf8_advance(&text, &len);
+ if (c == ~0UL) {
+ i_push_error(0, "invalid UTF8 character");
+ return 0;
+ }
+ }
+ else {
+ c = (unsigned char)*text++;
+ --len;
+ }
+
+ if (TT_VALID(handle->char_map)) {
+ index = TT_Char_Index(handle->char_map, c);
+ }
+ else {
+ index = (c - ' ' + 1) < 0 ? 0 : (c - ' ' + 1);
+ if (index >= handle->properties.num_Glyphs)
+ index = 0;
+ }
+ *out++ = index != 0;
+ ++count;
+ }
+
+ return count;
+}
+
+/*
+=item i_tt_destroy(handle)
+
+Clears the data taken by a font including all cached data such as
+pixmaps and glyphs
+
+ handle - pointer to font handle
+
+=cut
+*/
+
+void
+i_tt_destroy( TT_Fonthandle *handle) {
+ TT_Close_Face( handle->face );
+ myfree( handle );
+
+ /* FIXME: Should these be freed automatically by the library?
+
+ TT_Done_Instance( instance );
+ void
+ i_tt_done_glyphs( void ) {
+ int i;
+
+ if ( !glyphs ) return;
+
+ for ( i = 0; i < 256; ++i ) TT_Done_Glyph( glyphs[i] );
+ free( glyphs );
+
+ glyphs = NULL;
+ }
+ */
+}
+
+
+/*
+ * FreeType Rendering functions
+ */
+
+
+/*
+=item i_tt_render_glyph(handle, gmetrics, bit, smallbit, x_off, y_off, smooth)
+
+Renders a single glyph into the bit rastermap (internal)
+
+ handle - pointer to font handle
+ gmetrics - the metrics for the glyph to be rendered
+ bit - large bitmap that is the destination for the text
+ smallbit - small bitmap that is used only if smooth is true
+ x_off - x offset of glyph
+ y_off - y offset of glyph
+ smooth - boolean (True: antialias on, False: antialias is off)
+
+=cut
+*/
+
+static
+void
+i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics, TT_Raster_Map *bit, TT_Raster_Map *small_bit, i_img_dim x_off, i_img_dim y_off, int smooth ) {
+
+ mm_log((1,"i_tt_render_glyph(glyph %p, gmetrics %p, bit %p, small_bit %p, x_off %" i_DF ", y_off %" i_DF ", smooth %d)\n",
+ USTRCT(glyph), gmetrics, bit, small_bit, i_DFc(x_off),
+ i_DFc(y_off), smooth));
+
+ if ( !smooth ) TT_Get_Glyph_Bitmap( glyph, bit, x_off * 64, y_off * 64);
+ else {
+ TT_F26Dot6 xmin, ymin, xmax, ymax;
+
+ xmin = gmetrics->bbox.xMin & -64;
+ ymin = gmetrics->bbox.yMin & -64;
+ xmax = (gmetrics->bbox.xMax + 63) & -64;
+ ymax = (gmetrics->bbox.yMax + 63) & -64;
+
+ i_tt_clear_raster_map( small_bit );
+ TT_Get_Glyph_Pixmap( glyph, small_bit, -xmin, -ymin );
+ i_tt_blit_or( bit, small_bit, xmin/64 + x_off, -ymin/64 - y_off );
+ }
+}
+
+
+/*
+=item i_tt_render_all_glyphs(handle, inst, bit, small_bit, cords, txt, len, smooth)
+
+calls i_tt_render_glyph to render each glyph into the bit rastermap (internal)
+
+ handle - pointer to font handle
+ inst - font instance
+ bit - large bitmap that is the destination for the text
+ smallbit - small bitmap that is used only if smooth is true
+ txt - string to render
+ len - length of the string to render
+ smooth - boolean (True: antialias on, False: antialias is off)
+
+=cut
+*/
+
+static
+int
+i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
+ TT_Raster_Map *small_bit, i_img_dim cords[6],
+ char const* txt, size_t len, int smooth, int utf8 ) {
+ unsigned long j;
+ TT_F26Dot6 x,y;
+
+ mm_log((1,"i_tt_render_all_glyphs( handle %p, inst %d, bit %p, small_bit %p, txt '%.*s', len %ld, smooth %d, utf8 %d)\n",
+ handle, inst, bit, small_bit, (int)len, txt, (long)len, smooth, utf8));
+
+ /*
+ y=-( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem )/(handle->properties.header->Units_Per_EM);
+ */
+
+ x=-cords[0]; /* FIXME: If you font is antialiased this should be expanded by one to allow for aa expansion and the allocation too - do before passing here */
+ y=-cords[4];
+
+ while (len) {
+ if (utf8) {
+ j = i_utf8_advance(&txt, &len);
+ if (j == ~0UL) {
+ i_push_error(0, "invalid UTF8 character");
+ return 0;
+ }
+ }
+ else {
+ j = (unsigned char)*txt++;
+ --len;
+ }
+ if ( !i_tt_get_glyph(handle,inst,j) )
+ continue;
+ i_tt_render_glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph,
+ &handle->instanceh[inst].gmetrics[TT_HASH(j)], bit,
+ small_bit, x, y, smooth );
+ x += handle->instanceh[inst].gmetrics[TT_HASH(j)].advance / 64;
+ }
+
+ return 1;
+}
+
+
+/*
+ * Functions to render rasters (single channel images) onto images
+ */
+
+/*
+=item i_tt_dump_raster_map2(im, bit, xb, yb, cl, smooth)
+
+Function to dump a raster onto an image in color used by i_tt_text() (internal).
+
+ im - image to dump raster on
+ bit - bitmap that contains the text to be dumped to im
+ xb, yb - coordinates, left edge and baseline
+ cl - color to use for text
+ smooth - boolean (True: antialias on, False: antialias is off)
+
+=cut
+*/
+
+static
+void
+i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, const i_color *cl, int smooth ) {
+ unsigned char *bmap;
+ i_img_dim x, y;
+ mm_log((1,"i_tt_dump_raster_map2(im %p, bit %p, xb %" i_DF ", yb %" i_DF ", cl %p)\n",
+ im, bit, i_DFc(xb), i_DFc(yb), cl));
+
+ bmap = bit->bitmap;
+
+ if ( smooth ) {
+
+ i_render r;
+ i_render_init(&r, im, bit->cols);
+ for(y=0;y<bit->rows;y++) {
+ i_render_color(&r, xb, yb+y, bit->cols, bmap + y*bit->cols, cl);
+ }
+ i_render_done(&r);
+ } else {
+ for(y=0;y<bit->rows;y++) {
+ unsigned mask = 0x80;
+ unsigned char *p = bmap + y * bit->cols;
+
+ for(x = 0; x < bit->width; x++) {
+ if (*p & mask) {
+ i_ppix(im, x+xb, y+yb, cl);
+ }
+ mask >>= 1;
+ if (!mask) {
+ mask = 0x80;
+ ++p;
+ }
+ }
+ }
+
+ }
+}
+
+
+/*
+=item i_tt_dump_raster_map_channel(im, bit, xb, yb, channel, smooth)
+
+Function to dump a raster onto a single channel image in color (internal)
+
+ im - image to dump raster on
+ bit - bitmap that contains the text to be dumped to im
+ xb, yb - coordinates, left edge and baseline
+ channel - channel to copy to
+ smooth - boolean (True: antialias on, False: antialias is off)
+
+=cut
+*/
+
+static
+void
+i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, int channel, int smooth ) {
+ unsigned char *bmap;
+ i_color val;
+ int c;
+ i_img_dim x,y;
+ int old_mask = im->ch_mask;
+ im->ch_mask = 1 << channel;
+
+ mm_log((1,"i_tt_dump_raster_channel(im %p, bit %p, xb %" i_DF ", yb %" i_DF ", channel %d)\n",
+ im, bit, i_DFc(xb), i_DFc(yb), channel));
+
+ bmap = bit->bitmap;
+
+ if ( smooth ) {
+ for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
+ c = bmap[y*(bit->cols)+x];
+ val.channel[channel] = c;
+ i_ppix(im,x+xb,y+yb,&val);
+ }
+ } else {
+ for(y=0;y<bit->rows;y++) {
+ unsigned mask = 0x80;
+ unsigned char *p = bmap + y * bit->cols;
+
+ for(x=0;x<bit->width;x++) {
+ val.channel[channel] = (*p & mask) ? 255 : 0;
+ i_ppix(im,x+xb,y+yb,&val);
+
+ mask >>= 1;
+ if (!mask) {
+ ++p;
+ mask = 0x80;
+ }
+ }
+ }
+ }
+ im->ch_mask = old_mask;
+}
+
+
+/*
+=item i_tt_rasterize(handle, bit, cords, points, txt, len, smooth)
+
+interface for generating single channel raster of text (internal)
+
+ handle - pointer to font handle
+ bit - the bitmap that is allocated, rendered into and NOT freed
+ cords - the bounding box (modified in place)
+ points - font size to use
+ txt - string to render
+ len - length of the string to render
+ smooth - boolean (True: antialias on, False: antialias is off)
+
+=cut
+*/
+
+static
+int
+i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, i_img_dim cords[6], double points, char const* txt, size_t len, int smooth, int utf8 ) {
+ int inst;
+ i_img_dim width, height;
+ TT_Raster_Map small_bit;
+
+ /* find or install an instance */
+ if ( (inst=i_tt_get_instance(handle,points,smooth)) < 0) {
+ mm_log((1,"i_tt_rasterize: get instance failed\n"));
+ return 0;
+ }
+
+ /* calculate bounding box */
+ if (!i_tt_bbox_inst( handle, inst, txt, len, cords, utf8 ))
+ return 0;
+
+
+ width = cords[2]-cords[0];
+ height = cords[5]-cords[4];
+
+ mm_log((1,"i_tt_rasterize: width=%" i_DF ", height=%" i_DF "\n",
+ i_DFc(width), i_DFc(height) ));
+
+ i_tt_init_raster_map ( bit, width, height, smooth );
+ i_tt_clear_raster_map( bit );
+ if ( smooth ) i_tt_init_raster_map( &small_bit, handle->instanceh[inst].imetrics.x_ppem + 32, height, smooth );
+
+ if (!i_tt_render_all_glyphs( handle, inst, bit, &small_bit, cords, txt, len,
+ smooth, utf8 )) {
+ if ( smooth )
+ i_tt_done_raster_map( &small_bit );
+ return 0;
+ }
+
+ if ( smooth ) i_tt_done_raster_map( &small_bit );
+ return 1;
+}
+
+
+
+/*
+ * Exported text rendering interfaces
+ */
+
+
+/*
+=item i_tt_cp(handle, im, xb, yb, channel, points, txt, len, smooth, utf8)
+
+Interface to text rendering into a single channel in an image
+
+ handle - pointer to font handle
+ im - image to render text on to
+ xb, yb - coordinates, left edge and baseline
+ channel - channel to render into
+ points - font size to use
+ txt - string to render
+ len - length of the string to render
+ smooth - boolean (True: antialias on, False: antialias is off)
+
+=cut
+*/
+
+undef_int
+i_tt_cp( TT_Fonthandle *handle, i_img *im, i_img_dim xb, i_img_dim yb, int channel, double points, char const* txt, size_t len, int smooth, int utf8, int align ) {
+
+ i_img_dim cords[BOUNDING_BOX_COUNT];
+ i_img_dim ascent, st_offset, y;
+ TT_Raster_Map bit;
+
+ i_clear_error();
+ if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0;
+
+ ascent=cords[BBOX_ASCENT];
+ st_offset=cords[BBOX_NEG_WIDTH];
+ y = align ? yb-ascent : yb;
+
+ i_tt_dump_raster_map_channel( im, &bit, xb-st_offset , y, channel, smooth );
+ i_tt_done_raster_map( &bit );
+
+ return 1;
+}
+
+
+/*
+=item i_tt_text(handle, im, xb, yb, cl, points, txt, len, smooth, utf8)
+
+Interface to text rendering in a single color onto an image
+
+ handle - pointer to font handle
+ im - image to render text on to
+ xb, yb - coordinates, left edge and baseline
+ cl - color to use for text
+ points - font size to use
+ txt - string to render
+ len - length of the string to render
+ smooth - boolean (True: antialias on, False: antialias is off)
+
+=cut
+*/
+
+undef_int
+i_tt_text( TT_Fonthandle *handle, i_img *im, i_img_dim xb, i_img_dim yb, const i_color *cl, double points, char const* txt, size_t len, int smooth, int utf8, int align) {
+ i_img_dim cords[BOUNDING_BOX_COUNT];
+ i_img_dim ascent, st_offset, y;
+ TT_Raster_Map bit;
+
+ i_clear_error();
+
+ if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0;
+
+ ascent=cords[BBOX_ASCENT];
+ st_offset=cords[BBOX_NEG_WIDTH];
+ y = align ? yb-ascent : yb;
+
+ i_tt_dump_raster_map2( im, &bit, xb+st_offset, y, cl, smooth );
+ i_tt_done_raster_map( &bit );
+
+ return 1;
+}
+
+
+/*
+=item i_tt_bbox_inst(handle, inst, txt, len, cords, utf8)
+
+Function to get texts bounding boxes given the instance of the font (internal)
+
+ handle - pointer to font handle
+ inst - font instance
+ txt - string to measure
+ len - length of the string to render
+ cords - the bounding box (modified in place)
+
+=cut
+*/
+
+static
+undef_int
+i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, size_t len, i_img_dim cords[BOUNDING_BOX_COUNT], int utf8 ) {
+ int upm, casc, cdesc, first;
+
+ int start = 0;
+ i_img_dim width = 0;
+ int gdescent = 0;
+ int gascent = 0;
+ int descent = 0;
+ int ascent = 0;
+ int rightb = 0;
+
+ unsigned long j;
+ unsigned char *ustr;
+ ustr=(unsigned char*)txt;
+
+ mm_log((1,"i_tt_box_inst(handle %p,inst %d,txt '%.*s', len %ld, utf8 %d)\n",
+ handle, inst, (int)len, txt, (long)len, utf8));
+
+ upm = handle->properties.header->Units_Per_EM;
+ gascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem + upm - 1) / upm;
+ gdescent = ( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem - upm + 1) / upm;
+
+ width = 0;
+ start = 0;
+
+ mm_log((1, "i_tt_box_inst: gascent=%d gdescent=%d\n", gascent, gdescent));
+
+ first=1;
+ while (len) {
+ if (utf8) {
+ j = i_utf8_advance(&txt, &len);
+ if (j == ~0UL) {
+ i_push_error(0, "invalid UTF8 character");
+ return 0;
+ }
+ }
+ else {
+ j = (unsigned char)*txt++;
+ --len;
+ }
+ if ( i_tt_get_glyph(handle,inst,j) ) {
+ TT_Glyph_Metrics *gm = handle->instanceh[inst].gmetrics + TT_HASH(j);
+ width += gm->advance / 64;
+ casc = (gm->bbox.yMax+63) / 64;
+ cdesc = (gm->bbox.yMin-63) / 64;
+
+ mm_log((1, "i_tt_box_inst: glyph='%c' casc=%d cdesc=%d\n",
+ (int)((j >= ' ' && j <= '~') ? j : '.'), casc, cdesc));
+
+ if (first) {
+ start = gm->bbox.xMin / 64;
+ ascent = (gm->bbox.yMax+63) / 64;
+ descent = (gm->bbox.yMin-63) / 64;
+ first = 0;
+ }
+ if (!len) { /* if at end of string */
+ /* the right-side bearing - in case the right-side of a
+ character goes past the right of the advance width,
+ as is common for italic fonts
+ */
+ rightb = gm->advance - gm->bearingX
+ - (gm->bbox.xMax - gm->bbox.xMin);
+ /* fprintf(stderr, "font info last: %d %d %d %d\n",
+ gm->bbox.xMax, gm->bbox.xMin, gm->advance, rightb); */
+ }
+
+ ascent = (ascent > casc ? ascent : casc );
+ descent = (descent < cdesc ? descent : cdesc);
+ }
+ }
+
+ cords[BBOX_NEG_WIDTH]=start;
+ cords[BBOX_GLOBAL_DESCENT]=gdescent;
+ cords[BBOX_POS_WIDTH]=width;
+ if (rightb < 0)
+ cords[BBOX_POS_WIDTH] -= rightb / 64;
+ cords[BBOX_GLOBAL_ASCENT]=gascent;
+ cords[BBOX_DESCENT]=descent;
+ cords[BBOX_ASCENT]=ascent;
+ cords[BBOX_ADVANCE_WIDTH] = width;
+ cords[BBOX_RIGHT_BEARING] = rightb / 64;
+
+ return BBOX_RIGHT_BEARING + 1;
+}
+
+
+/*
+=item i_tt_bbox(handle, points, txt, len, cords, utf8)
+
+Interface to get a strings bounding box
+
+ handle - pointer to font handle
+ points - font size to use
+ txt - string to render
+ len - length of the string to render
+ cords - the bounding box (modified in place)
+
+=cut
+*/
+
+undef_int
+i_tt_bbox( TT_Fonthandle *handle, double points,const char *txt,size_t len,i_img_dim cords[6], int utf8) {
+ int inst;
+
+ i_clear_error();
+ mm_log((1,"i_tt_box(handle %p,points %f,txt '%.*s', len %ld, utf8 %d)\n",
+ handle, points, (int)len, txt, (long)len, utf8));
+
+ if ( (inst=i_tt_get_instance(handle,points,-1)) < 0) {
+ i_push_errorf(0, "i_tt_get_instance(%g)", points);
+ mm_log((1,"i_tt_text: get instance failed\n"));
+ return 0;
+ }
+
+ return i_tt_bbox_inst(handle, inst, txt, len, cords, utf8);
+}
+
+/*
+=item i_tt_face_name(handle, name_buf, name_buf_size)
+
+Retrieve's the font's postscript name.
+
+This is complicated by the need to handle encodings and so on.
+
+=cut
+ */
+size_t
+i_tt_face_name(TT_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
+ TT_Face_Properties props;
+ int name_count;
+ int i;
+ TT_UShort platform_id, encoding_id, lang_id, name_id;
+ TT_UShort name_len;
+ TT_String *name;
+ int want_index = -1; /* an acceptable but not perfect name */
+ int score = 0;
+
+ i_clear_error();
+
+ TT_Get_Face_Properties(handle->face, &props);
+ name_count = props.num_Names;
+ for (i = 0; i < name_count; ++i) {
+ TT_Get_Name_ID(handle->face, i, &platform_id, &encoding_id, &lang_id,
+ &name_id);
+
+ TT_Get_Name_String(handle->face, i, &name, &name_len);
+
+ if (platform_id != TT_PLATFORM_APPLE_UNICODE && name_len
+ && name_id == TT_NAME_ID_PS_NAME) {
+ int might_want_index = -1;
+ int might_score = 0;
+ if ((platform_id == TT_PLATFORM_MACINTOSH && encoding_id == TT_MAC_ID_ROMAN)
+ ||
+ (platform_id == TT_PLATFORM_MICROSOFT && encoding_id == TT_MS_LANGID_ENGLISH_UNITED_STATES)) {
+ /* exactly what we want */
+ want_index = i;
+ break;
+ }
+
+ if (platform_id == TT_PLATFORM_MICROSOFT
+ && (encoding_id & 0xFF) == TT_MS_LANGID_ENGLISH_GENERAL) {
+ /* any english is good */
+ might_want_index = i;
+ might_score = 9;
+ }
+ /* there might be something in between */
+ else {
+ /* anything non-unicode is better than nothing */
+ might_want_index = i;
+ might_score = 1;
+ }
+ if (might_score > score) {
+ score = might_score;
+ want_index = might_want_index;
+ }
+ }
+ }
+
+ if (want_index != -1) {
+ TT_Get_Name_String(handle->face, want_index, &name, &name_len);
+
+ strncpy(name_buf, name, name_buf_size);
+ name_buf[name_buf_size-1] = '\0';
+
+ return strlen(name) + 1;
+ }
+ else {
+ i_push_error(0, "no face name present");
+ return 0;
+ }
+}
+
+void i_tt_dump_names(TT_Fonthandle *handle) {
+ TT_Face_Properties props;
+ int name_count;
+ int i;
+ TT_UShort platform_id, encoding_id, lang_id, name_id;
+ TT_UShort name_len;
+ TT_String *name;
+
+ TT_Get_Face_Properties(handle->face, &props);
+ name_count = props.num_Names;
+ for (i = 0; i < name_count; ++i) {
+ TT_Get_Name_ID(handle->face, i, &platform_id, &encoding_id, &lang_id,
+ &name_id);
+ TT_Get_Name_String(handle->face, i, &name, &name_len);
+
+ printf("# %d: plat %d enc %d lang %d name %d value ", i, platform_id,
+ encoding_id, lang_id, name_id);
+ if (platform_id == TT_PLATFORM_APPLE_UNICODE) {
+ printf("(unicode)\n");
+ }
+ else {
+ printf("'%s'\n", name);
+ }
+ }
+ fflush(stdout);
+}
+
+size_t
+i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf,
+ size_t name_buf_size) {
+#ifdef FTXPOST
+ TT_Error rc;
+ TT_String *psname;
+ TT_UShort index;
+
+ i_clear_error();
+
+ if (!handle->loaded_names) {
+ TT_Post post;
+ mm_log((1, "Loading PS Names"));
+ handle->load_cond = TT_Load_PS_Names(handle->face, &post);
+ ++handle->loaded_names;
+ }
+
+ if (handle->load_cond) {
+ i_push_errorf(handle->load_cond, "error loading names (%#x)",
+ (unsigned)handle->load_cond);
+ return 0;
+ }
+
+ index = TT_Char_Index(handle->char_map, ch);
+ if (!index) {
+ i_push_error(0, "no such character");
+ return 0;
+ }
+
+ rc = TT_Get_PS_Name(handle->face, index, &psname);
+
+ if (rc) {
+ i_push_error(rc, "error getting name");
+ return 0;
+ }
+
+ strncpy(name_buf, psname, name_buf_size);
+ name_buf[name_buf_size-1] = '\0';
+
+ return strlen(psname) + 1;
+#else
+ mm_log((1, "FTXPOST extension not enabled\n"));
+ i_clear_error();
+ i_push_error(0, "Use of FTXPOST extension disabled");
+
+ return 0;
+#endif
+}
+
+/*
+=item i_tt_push_error(code)
+
+Push an error message and code onto the Imager error stack.
+
+=cut
+*/
+static void
+i_tt_push_error(TT_Error rc) {
+#ifdef FTXERR18
+ TT_String const *msg = TT_ErrToString18(rc);
+
+ i_push_error(rc, msg);
+#else
+ i_push_errorf(rc, "Error code 0x%04x", (unsigned)rc);
+#endif
+}
+
+#endif /* HAVE_LIBTT */
+
+
+/*
+=back
+
+=head1 AUTHOR
+
+Arnar M. Hrafnkelsson <addi@umich.edu>
+
+=head1 SEE ALSO
+
+Imager(3)
+
+=cut
+*/
+++ /dev/null
-#include "imager.h"
-#include "imrender.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-
-
-/*
-=head1 NAME
-
-fontft1.c - Freetype 1.x font driver for Imager
-
-=head1 SYNOPSIS
-
- handle = i_tt_new(path_to_ttf);
- rc = i_tt_bbox(handle, points, "foo", 3, int cords[6], utf8);
- i_tt_destroy(handle);
-
- // and much more
-
-=head1 DESCRIPTION
-
-fontft1.c implements font creation, rendering, bounding box functions and
-more for Imager using Freetype 1.x.
-
-In general this driver should be ignored in favour of the FT2 driver.
-
-=head1 FUNCTION REFERENCE
-
-Some of these functions are internal.
-
-=over
-
-=cut
-
-*/
-
-
-/* Truetype font support */
-/* These are enabled by default when configuring Freetype 1.x
- I haven't a clue how to reliably detect it at compile time.
-
- We need a compilation probe in Makefile.PL
-*/
-#define FTXPOST 1
-#define FTXERR18 1
-
-#include <freetype.h>
-#define TT_CHC 5
-
-#ifdef FTXPOST
-#include <ftxpost.h>
-#endif
-
-#ifdef FTXERR18
-#include <ftxerr18.h>
-#endif
-
-/* some versions of FT1.x don't seem to define this - it's font defined
- so it won't change */
-#ifndef TT_MS_LANGID_ENGLISH_GENERAL
-#define TT_MS_LANGID_ENGLISH_GENERAL 0x0409
-#endif
-
-static im_slot_t slot = -1;
-
-/* convert a code point into an index in the glyph cache */
-#define TT_HASH(x) ((x) & 0xFF)
-
-typedef struct {
- int initialized;
- TT_Engine engine;
-} i_tt_engine;
-
-typedef struct i_glyph_entry_ {
- TT_Glyph glyph;
- unsigned long ch;
-} i_tt_glyph_entry;
-
-#define TT_NOCHAR (~0UL)
-
-struct TT_Instancehandle_ {
- TT_Instance instance;
- TT_Instance_Metrics imetrics;
- TT_Glyph_Metrics gmetrics[256];
- i_tt_glyph_entry glyphs[256];
- int smooth;
- int order;
- i_img_dim ptsize;
-};
-
-typedef struct TT_Instancehandle_ TT_Instancehandle;
-
-struct TT_Fonthandle_ {
- TT_Face face;
- TT_Face_Properties properties;
- TT_Instancehandle instanceh[TT_CHC];
- TT_CharMap char_map;
-#ifdef FTXPOST
- int loaded_names;
- TT_Error load_cond;
-#endif
-};
-
-/* Defines */
-
-#define USTRCT(x) ((x).z)
-#define TT_VALID( handle ) ( ( handle ).z != NULL )
-
-static void i_tt_push_error(TT_Error rc);
-static void i_tt_uninit(void *);
-
-/* Prototypes */
-
-static int i_tt_get_instance( TT_Fonthandle *handle, i_img_dim points, int smooth );
-static void i_tt_init_raster_map( TT_Raster_Map* bit, i_img_dim width, i_img_dim height, int smooth );
-static void i_tt_done_raster_map( TT_Raster_Map *bit );
-static void i_tt_clear_raster_map( TT_Raster_Map* bit );
-static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,i_img_dim x_off, i_img_dim y_off );
-static int i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j );
-static void
-i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics,
- TT_Raster_Map *bit, TT_Raster_Map *small_bit,
- i_img_dim x_off, i_img_dim y_off, int smooth );
-static int
-i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
- TT_Raster_Map *small_bit, i_img_dim cords[6],
- char const* txt, size_t len, int smooth, int utf8 );
-static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, const i_color *cl, int smooth );
-static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, int channel, int smooth );
-static int
-i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, i_img_dim cords[6],
- double points, char const* txt, size_t len, int smooth, int utf8 );
-static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, size_t len, i_img_dim cords[6], int utf8 );
-
-
-/* static globals needed */
-
-static int LTT_dpi = 72; /* FIXME: this ought to be a part of the call interface */
-static int LTT_hinted = 1; /* FIXME: this too */
-
-
-/*
- * FreeType interface
- */
-
-void
-i_tt_start(void) {
- if (slot == -1)
- slot = im_context_slot_new(i_tt_uninit, "TT");
-}
-
-
-/*
-=item init_tt()
-
-Initializes the freetype font rendering engine (if needed)
-
-=cut
-*/
-
-static i_tt_engine *
-i_init_tt(void) {
- TT_Error error;
- im_context_t ctx = im_get_context();
- TT_Byte palette[] = { 0, 64, 127, 191, 255 };
- i_tt_engine *result = im_context_slot_get(ctx, slot);
-
- i_clear_error();
-
- if (result == NULL) {
- result = mymalloc(sizeof(i_tt_engine));
- memset(result, 0, sizeof(*result));
- im_context_slot_set(ctx, slot, result);
- mm_log((1, "allocated FT1 state %p\n", result));
- }
-
- mm_log((1,"init_tt()\n"));
-
- if (result->initialized)
- return result;
-
- error = TT_Init_FreeType( &result->engine );
- if ( error ){
- mm_log((1,"Initialization of freetype failed, code = 0x%x\n",
- (unsigned)error));
- i_tt_push_error(error);
- i_push_error(0, "Could not initialize freetype 1.x");
- return NULL;
- }
-
-#ifdef FTXPOST
- error = TT_Init_Post_Extension( result->engine );
- if (error) {
- mm_log((1, "Initialization of Post extension failed = 0x%x\n",
- (unsigned)error));
-
- i_tt_push_error(error);
- i_push_error(0, "Could not initialize FT 1.x POST extension");
- return NULL;
- }
-#endif
-
- error = TT_Set_Raster_Gray_Palette(result->engine, palette);
- if (error) {
- mm_log((1, "Initialization of gray levels failed = 0x%x\n",
- (unsigned)error));
- i_tt_push_error(error);
- i_push_error(0, "Could not initialize FT 1.x POST extension");
- return NULL;
- }
-
- mm_log((1, "initialized FT1 state %p\n", result));
-
- result->initialized = 1;
-
- return result;
-}
-
-static void
-i_tt_uninit(void *p) {
- i_tt_engine *tteng = p;
-
- if (tteng->initialized) {
- mm_log((1, "finalizing FT1 state %p\n", tteng));
- TT_Done_FreeType(tteng->engine);
- }
- mm_log((1, "freeing FT1 state %p\n", tteng));
- myfree(tteng);
-}
-
-/*
-=item i_tt_get_instance(handle, points, smooth)
-
-Finds a points+smooth instance or if one doesn't exist in the cache
-allocates room and returns its cache entry
-
- fontname - path to the font to load
- handle - handle to the font.
- points - points of the requested font
- smooth - boolean (True: antialias on, False: antialias is off)
-
-=cut
-*/
-
-static
-int
-i_tt_get_instance( TT_Fonthandle *handle, i_img_dim points, int smooth ) {
- int i,idx;
- TT_Error error;
-
- mm_log((1,"i_tt_get_instance(handle %p, points %" i_DF ", smooth %d)\n",
- handle, i_DFc(points), smooth));
-
- if (smooth == -1) { /* Smooth doesn't matter for this search */
- for(i=0;i<TT_CHC;i++) {
- if (handle->instanceh[i].ptsize==points) {
- mm_log((1,"i_tt_get_instance: in cache - (non selective smoothing search) returning %d\n",i));
- return i;
- }
- }
- smooth=1; /* We will be adding a font - add it as smooth then */
- } else { /* Smooth doesn't matter for this search */
- for(i=0;i<TT_CHC;i++) {
- if (handle->instanceh[i].ptsize == points
- && handle->instanceh[i].smooth == smooth) {
- mm_log((1,"i_tt_get_instance: in cache returning %d\n",i));
- return i;
- }
- }
- }
-
- /* Found the instance in the cache - return the cache index */
-
- for(idx=0;idx<TT_CHC;idx++) {
- if (!(handle->instanceh[idx].order)) break; /* find the lru item */
- }
-
- mm_log((1,"i_tt_get_instance: lru item is %d\n",idx));
- mm_log((1,"i_tt_get_instance: lru pointer %p\n",
- USTRCT(handle->instanceh[idx].instance) ));
-
- if ( USTRCT(handle->instanceh[idx].instance) ) {
- mm_log((1,"i_tt_get_instance: freeing lru item from cache %d\n",idx));
-
- /* Free cached glyphs */
- for(i=0;i<256;i++)
- if ( USTRCT(handle->instanceh[idx].glyphs[i].glyph) )
- TT_Done_Glyph( handle->instanceh[idx].glyphs[i].glyph );
-
- for(i=0;i<256;i++) {
- handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR;
- USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL;
- }
-
- /* Free instance if needed */
- TT_Done_Instance( handle->instanceh[idx].instance );
- }
-
- /* create and initialize instance */
- /* FIXME: probably a memory leak on fail */
-
- (void) (( error = TT_New_Instance( handle->face, &handle->instanceh[idx].instance ) ) ||
- ( error = TT_Set_Instance_Resolutions( handle->instanceh[idx].instance, LTT_dpi, LTT_dpi ) ) ||
- ( error = TT_Set_Instance_CharSize( handle->instanceh[idx].instance, points*64 ) ) );
-
- if ( error ) {
- mm_log((1, "Could not create and initialize instance: error %x.\n",
- (unsigned)error ));
- return -1;
- }
-
- /* Now that the instance should the inplace we need to lower all of the
- ru counts and put `this' one with the highest entry */
-
- for(i=0;i<TT_CHC;i++) handle->instanceh[i].order--;
-
- handle->instanceh[idx].order=TT_CHC-1;
- handle->instanceh[idx].ptsize=points;
- handle->instanceh[idx].smooth=smooth;
- TT_Get_Instance_Metrics( handle->instanceh[idx].instance, &(handle->instanceh[idx].imetrics) );
-
- /* Zero the memory for the glyph storage so they are not thought as
- cached if they haven't been cached since this new font was loaded */
-
- for(i=0;i<256;i++) {
- handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR;
- USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL;
- }
-
- return idx;
-}
-
-
-/*
-=item i_tt_new(fontname)
-
-Creates a new font handle object, finds a character map and initialise the
-the font handle's cache
-
- fontname - path to the font to load
-
-=cut
-*/
-
-TT_Fonthandle*
-i_tt_new(const char *fontname) {
- TT_Error error;
- TT_Fonthandle *handle;
- unsigned short i,n;
- unsigned short platform,encoding;
- i_tt_engine *tteng;
-
- if ((tteng = i_init_tt()) == NULL) {
- i_push_error(0, "Could not initialize FT1 engine");
- return NULL;
- }
-
- i_clear_error();
-
- mm_log((1,"i_tt_new(fontname '%s')\n",fontname));
-
- /* allocate memory for the structure */
-
- handle = mymalloc( sizeof(TT_Fonthandle) ); /* checked 5Nov05 tonyc */
-
- /* load the typeface */
- error = TT_Open_Face( tteng->engine, fontname, &handle->face );
- if ( error ) {
- if ( error == TT_Err_Could_Not_Open_File ) {
- mm_log((1, "Could not find/open %s.\n", fontname ));
- }
- else {
- mm_log((1, "Error while opening %s, error code = 0x%x.\n",fontname,
- (unsigned)error ));
- }
- i_tt_push_error(error);
- return NULL;
- }
-
- TT_Get_Face_Properties( handle->face, &(handle->properties) );
-
- /* First, look for a Unicode charmap */
- n = handle->properties.num_CharMaps;
- USTRCT( handle->char_map )=NULL; /* Invalidate character map */
-
- for ( i = 0; i < n; i++ ) {
- TT_Get_CharMap_ID( handle->face, i, &platform, &encoding );
- if ( (platform == 3 && encoding == 1 )
- || (platform == 0 && encoding == 0 ) ) {
- mm_log((2,"i_tt_new - found char map platform %u encoding %u\n",
- platform, encoding));
- TT_Get_CharMap( handle->face, i, &(handle->char_map) );
- break;
- }
- }
- if (!USTRCT(handle->char_map) && n != 0) {
- /* just use the first one */
- TT_Get_CharMap( handle->face, 0, &(handle->char_map));
- }
-
- /* Zero the pointsizes - and ordering */
-
- for(i=0;i<TT_CHC;i++) {
- USTRCT(handle->instanceh[i].instance)=NULL;
- handle->instanceh[i].order=i;
- handle->instanceh[i].ptsize=0;
- handle->instanceh[i].smooth=-1;
- }
-
-#ifdef FTXPOST
- handle->loaded_names = 0;
-#endif
-
- mm_log((1,"i_tt_new <- %p\n",handle));
- return handle;
-}
-
-
-
-/*
- * raster map management
- */
-
-/*
-=item i_tt_init_raster_map(bit, width, height, smooth)
-
-Allocates internal memory for the bitmap as needed by the parameters (internal)
-
- bit - bitmap to allocate into
- width - width of the bitmap
- height - height of the bitmap
- smooth - boolean (True: antialias on, False: antialias is off)
-
-=cut
-*/
-
-static
-void
-i_tt_init_raster_map( TT_Raster_Map* bit, i_img_dim width, i_img_dim height, int smooth ) {
-
- mm_log((1,"i_tt_init_raster_map( bit %p, width %" i_DF ", height %" i_DF
- ", smooth %d)\n", bit, i_DFc(width), i_DFc(height), smooth));
-
- bit->rows = height;
- bit->width = ( width + 3 ) & -4;
- bit->flow = TT_Flow_Down;
-
- if ( smooth ) {
- bit->cols = bit->width;
- bit->size = bit->rows * bit->width;
- } else {
- bit->cols = ( bit->width + 7 ) / 8; /* convert to # of bytes */
- bit->size = bit->rows * bit->cols; /* number of bytes in buffer */
- }
-
- /* rows can be 0 for some glyphs, for example ' ' */
- if (bit->rows && bit->size / bit->rows != bit->cols) {
- i_fatal(0, "Integer overflow calculating bitmap size (%d, %d)\n",
- bit->width, bit->rows);
- }
-
- mm_log((1,"i_tt_init_raster_map: bit->width %d, bit->cols %d, bit->rows %d, bit->size %ld)\n", bit->width, bit->cols, bit->rows, bit->size ));
-
- bit->bitmap = (void *) mymalloc( bit->size ); /* checked 6Nov05 tonyc */
- if ( !bit->bitmap ) i_fatal(0,"Not enough memory to allocate bitmap (%d)!\n",bit->size );
-}
-
-
-/*
-=item i_tt_clear_raster_map(bit)
-
-Frees the bitmap data and sets pointer to NULL (internal)
-
- bit - bitmap to free
-
-=cut
-*/
-
-static
-void
-i_tt_done_raster_map( TT_Raster_Map *bit ) {
- myfree( bit->bitmap );
- bit->bitmap = NULL;
-}
-
-
-/*
-=item i_tt_clear_raster_map(bit)
-
-Clears the specified bitmap (internal)
-
- bit - bitmap to zero
-
-=cut
-*/
-
-
-static
-void
-i_tt_clear_raster_map( TT_Raster_Map* bit ) {
- memset( bit->bitmap, 0, bit->size );
-}
-
-
-/*
-=item i_tt_blit_or(dst, src, x_off, y_off)
-
-function that blits one raster map into another (internal)
-
- dst - destination bitmap
- src - source bitmap
- x_off - x offset into the destination bitmap
- y_off - y offset into the destination bitmap
-
-=cut
-*/
-
-static
-void
-i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,i_img_dim x_off, i_img_dim y_off ) {
- i_img_dim x, y;
- i_img_dim x1, x2, y1, y2;
- unsigned char *s, *d;
-
- x1 = x_off < 0 ? -x_off : 0;
- y1 = y_off < 0 ? -y_off : 0;
-
- x2 = (int)dst->cols - x_off;
- if ( x2 > src->cols ) x2 = src->cols;
-
- y2 = (int)dst->rows - y_off;
- if ( y2 > src->rows ) y2 = src->rows;
-
- if ( x1 >= x2 ) return;
-
- /* do the real work now */
-
- for ( y = y1; y < y2; ++y ) {
- s = ( (unsigned char*)src->bitmap ) + y * src->cols + x1;
- d = ( (unsigned char*)dst->bitmap ) + ( y + y_off ) * dst->cols + x1 + x_off;
-
- for ( x = x1; x < x2; ++x ) {
- if (*s > *d)
- *d = *s;
- d++;
- s++;
- }
- }
-}
-
-/* useful for debugging */
-#if 0
-
-static void dump_raster_map(FILE *out, TT_Raster_Map *bit ) {
- int x, y;
- fprintf(out, "cols %d rows %d flow %d\n", bit->cols, bit->rows, bit->flow);
- for (y = 0; y < bit->rows; ++y) {
- fprintf(out, "%2d:", y);
- for (x = 0; x < bit->cols; ++x) {
- if ((x & 7) == 0 && x) putc(' ', out);
- fprintf(out, "%02x", ((unsigned char *)bit->bitmap)[y*bit->cols+x]);
- }
- putc('\n', out);
- }
-}
-
-#endif
-
-/*
-=item i_tt_get_glyph(handle, inst, j)
-
-Function to see if a glyph exists and if so cache it (internal)
-
- handle - pointer to font handle
- inst - font instance
- j - charcode of glyph
-
-=cut
-*/
-
-static
-int
-i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j) {
- unsigned short load_flags, code;
- TT_Error error;
-
- mm_log((1, "i_tt_get_glyph(handle %p, inst %d, j %lu (%c))\n",
- handle,inst,j, (int)((j >= ' ' && j <= '~') ? j : '.')));
-
- /*mm_log((1, "handle->instanceh[inst].glyphs[j]=0x%08X\n",handle->instanceh[inst].glyphs[j] ));*/
-
- if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)
- && handle->instanceh[inst].glyphs[TT_HASH(j)].ch == j) {
- mm_log((1,"i_tt_get_glyph: %lu in cache\n",j));
- return 1;
- }
-
- if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph) ) {
- /* clean up the entry */
- TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
- USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
- handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR;
- }
-
- /* Ok - it wasn't cached - try to get it in */
- load_flags = TTLOAD_SCALE_GLYPH;
- if ( LTT_hinted ) load_flags |= TTLOAD_HINT_GLYPH;
-
- if ( !TT_VALID(handle->char_map) ) {
- code = (j - ' ' + 1) < 0 ? 0 : (j - ' ' + 1);
- if ( code >= handle->properties.num_Glyphs ) code = 0;
- } else code = TT_Char_Index( handle->char_map, j );
-
- if ( (error = TT_New_Glyph( handle->face, &handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)) ) {
- mm_log((1, "Cannot allocate and load glyph: error %#x.\n", (unsigned)error ));
- i_push_error(error, "TT_New_Glyph()");
- return 0;
- }
- if ( (error = TT_Load_Glyph( handle->instanceh[inst].instance, handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, code, load_flags)) ) {
- mm_log((1, "Cannot allocate and load glyph: error %#x.\n", (unsigned)error ));
- /* Don't leak */
- TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
- USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
- i_push_error(error, "TT_Load_Glyph()");
- return 0;
- }
-
- /* At this point the glyph should be allocated and loaded */
- handle->instanceh[inst].glyphs[TT_HASH(j)].ch = j;
-
- /* Next get the glyph metrics */
- error = TT_Get_Glyph_Metrics( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph,
- &handle->instanceh[inst].gmetrics[TT_HASH(j)] );
- if (error) {
- mm_log((1, "TT_Get_Glyph_Metrics: error %#x.\n", (unsigned)error ));
- TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
- USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
- handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR;
- i_push_error(error, "TT_Get_Glyph_Metrics()");
- return 0;
- }
-
- return 1;
-}
-
-/*
-=item i_tt_has_chars(handle, text, len, utf8, out)
-
-Check if the given characters are defined by the font. Note that len
-is the number of bytes, not the number of characters (when utf8 is
-non-zero).
-
-Returns the number of characters that were checked.
-
-=cut
-*/
-
-size_t
-i_tt_has_chars(TT_Fonthandle *handle, char const *text, size_t len, int utf8,
- char *out) {
- size_t count = 0;
- mm_log((1, "i_tt_has_chars(handle %p, text %p, len %ld, utf8 %d)\n",
- handle, text, (long)len, utf8));
-
- while (len) {
- unsigned long c;
- int index;
- if (utf8) {
- c = i_utf8_advance(&text, &len);
- if (c == ~0UL) {
- i_push_error(0, "invalid UTF8 character");
- return 0;
- }
- }
- else {
- c = (unsigned char)*text++;
- --len;
- }
-
- if (TT_VALID(handle->char_map)) {
- index = TT_Char_Index(handle->char_map, c);
- }
- else {
- index = (c - ' ' + 1) < 0 ? 0 : (c - ' ' + 1);
- if (index >= handle->properties.num_Glyphs)
- index = 0;
- }
- *out++ = index != 0;
- ++count;
- }
-
- return count;
-}
-
-/*
-=item i_tt_destroy(handle)
-
-Clears the data taken by a font including all cached data such as
-pixmaps and glyphs
-
- handle - pointer to font handle
-
-=cut
-*/
-
-void
-i_tt_destroy( TT_Fonthandle *handle) {
- TT_Close_Face( handle->face );
- myfree( handle );
-
- /* FIXME: Should these be freed automatically by the library?
-
- TT_Done_Instance( instance );
- void
- i_tt_done_glyphs( void ) {
- int i;
-
- if ( !glyphs ) return;
-
- for ( i = 0; i < 256; ++i ) TT_Done_Glyph( glyphs[i] );
- free( glyphs );
-
- glyphs = NULL;
- }
- */
-}
-
-
-/*
- * FreeType Rendering functions
- */
-
-
-/*
-=item i_tt_render_glyph(handle, gmetrics, bit, smallbit, x_off, y_off, smooth)
-
-Renders a single glyph into the bit rastermap (internal)
-
- handle - pointer to font handle
- gmetrics - the metrics for the glyph to be rendered
- bit - large bitmap that is the destination for the text
- smallbit - small bitmap that is used only if smooth is true
- x_off - x offset of glyph
- y_off - y offset of glyph
- smooth - boolean (True: antialias on, False: antialias is off)
-
-=cut
-*/
-
-static
-void
-i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics, TT_Raster_Map *bit, TT_Raster_Map *small_bit, i_img_dim x_off, i_img_dim y_off, int smooth ) {
-
- mm_log((1,"i_tt_render_glyph(glyph %p, gmetrics %p, bit %p, small_bit %p, x_off %" i_DF ", y_off %" i_DF ", smooth %d)\n",
- USTRCT(glyph), gmetrics, bit, small_bit, i_DFc(x_off),
- i_DFc(y_off), smooth));
-
- if ( !smooth ) TT_Get_Glyph_Bitmap( glyph, bit, x_off * 64, y_off * 64);
- else {
- TT_F26Dot6 xmin, ymin, xmax, ymax;
-
- xmin = gmetrics->bbox.xMin & -64;
- ymin = gmetrics->bbox.yMin & -64;
- xmax = (gmetrics->bbox.xMax + 63) & -64;
- ymax = (gmetrics->bbox.yMax + 63) & -64;
-
- i_tt_clear_raster_map( small_bit );
- TT_Get_Glyph_Pixmap( glyph, small_bit, -xmin, -ymin );
- i_tt_blit_or( bit, small_bit, xmin/64 + x_off, -ymin/64 - y_off );
- }
-}
-
-
-/*
-=item i_tt_render_all_glyphs(handle, inst, bit, small_bit, cords, txt, len, smooth)
-
-calls i_tt_render_glyph to render each glyph into the bit rastermap (internal)
-
- handle - pointer to font handle
- inst - font instance
- bit - large bitmap that is the destination for the text
- smallbit - small bitmap that is used only if smooth is true
- txt - string to render
- len - length of the string to render
- smooth - boolean (True: antialias on, False: antialias is off)
-
-=cut
-*/
-
-static
-int
-i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
- TT_Raster_Map *small_bit, i_img_dim cords[6],
- char const* txt, size_t len, int smooth, int utf8 ) {
- unsigned long j;
- TT_F26Dot6 x,y;
-
- mm_log((1,"i_tt_render_all_glyphs( handle %p, inst %d, bit %p, small_bit %p, txt '%.*s', len %ld, smooth %d, utf8 %d)\n",
- handle, inst, bit, small_bit, (int)len, txt, (long)len, smooth, utf8));
-
- /*
- y=-( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem )/(handle->properties.header->Units_Per_EM);
- */
-
- x=-cords[0]; /* FIXME: If you font is antialiased this should be expanded by one to allow for aa expansion and the allocation too - do before passing here */
- y=-cords[4];
-
- while (len) {
- if (utf8) {
- j = i_utf8_advance(&txt, &len);
- if (j == ~0UL) {
- i_push_error(0, "invalid UTF8 character");
- return 0;
- }
- }
- else {
- j = (unsigned char)*txt++;
- --len;
- }
- if ( !i_tt_get_glyph(handle,inst,j) )
- continue;
- i_tt_render_glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph,
- &handle->instanceh[inst].gmetrics[TT_HASH(j)], bit,
- small_bit, x, y, smooth );
- x += handle->instanceh[inst].gmetrics[TT_HASH(j)].advance / 64;
- }
-
- return 1;
-}
-
-
-/*
- * Functions to render rasters (single channel images) onto images
- */
-
-/*
-=item i_tt_dump_raster_map2(im, bit, xb, yb, cl, smooth)
-
-Function to dump a raster onto an image in color used by i_tt_text() (internal).
-
- im - image to dump raster on
- bit - bitmap that contains the text to be dumped to im
- xb, yb - coordinates, left edge and baseline
- cl - color to use for text
- smooth - boolean (True: antialias on, False: antialias is off)
-
-=cut
-*/
-
-static
-void
-i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, const i_color *cl, int smooth ) {
- unsigned char *bmap;
- i_img_dim x, y;
- mm_log((1,"i_tt_dump_raster_map2(im %p, bit %p, xb %" i_DF ", yb %" i_DF ", cl %p)\n",
- im, bit, i_DFc(xb), i_DFc(yb), cl));
-
- bmap = bit->bitmap;
-
- if ( smooth ) {
-
- i_render r;
- i_render_init(&r, im, bit->cols);
- for(y=0;y<bit->rows;y++) {
- i_render_color(&r, xb, yb+y, bit->cols, bmap + y*bit->cols, cl);
- }
- i_render_done(&r);
- } else {
- for(y=0;y<bit->rows;y++) {
- unsigned mask = 0x80;
- unsigned char *p = bmap + y * bit->cols;
-
- for(x = 0; x < bit->width; x++) {
- if (*p & mask) {
- i_ppix(im, x+xb, y+yb, cl);
- }
- mask >>= 1;
- if (!mask) {
- mask = 0x80;
- ++p;
- }
- }
- }
-
- }
-}
-
-
-/*
-=item i_tt_dump_raster_map_channel(im, bit, xb, yb, channel, smooth)
-
-Function to dump a raster onto a single channel image in color (internal)
-
- im - image to dump raster on
- bit - bitmap that contains the text to be dumped to im
- xb, yb - coordinates, left edge and baseline
- channel - channel to copy to
- smooth - boolean (True: antialias on, False: antialias is off)
-
-=cut
-*/
-
-static
-void
-i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, int channel, int smooth ) {
- unsigned char *bmap;
- i_color val;
- int c;
- i_img_dim x,y;
- int old_mask = im->ch_mask;
- im->ch_mask = 1 << channel;
-
- mm_log((1,"i_tt_dump_raster_channel(im %p, bit %p, xb %" i_DF ", yb %" i_DF ", channel %d)\n",
- im, bit, i_DFc(xb), i_DFc(yb), channel));
-
- bmap = bit->bitmap;
-
- if ( smooth ) {
- for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
- c = bmap[y*(bit->cols)+x];
- val.channel[channel] = c;
- i_ppix(im,x+xb,y+yb,&val);
- }
- } else {
- for(y=0;y<bit->rows;y++) {
- unsigned mask = 0x80;
- unsigned char *p = bmap + y * bit->cols;
-
- for(x=0;x<bit->width;x++) {
- val.channel[channel] = (*p & mask) ? 255 : 0;
- i_ppix(im,x+xb,y+yb,&val);
-
- mask >>= 1;
- if (!mask) {
- ++p;
- mask = 0x80;
- }
- }
- }
- }
- im->ch_mask = old_mask;
-}
-
-
-/*
-=item i_tt_rasterize(handle, bit, cords, points, txt, len, smooth)
-
-interface for generating single channel raster of text (internal)
-
- handle - pointer to font handle
- bit - the bitmap that is allocated, rendered into and NOT freed
- cords - the bounding box (modified in place)
- points - font size to use
- txt - string to render
- len - length of the string to render
- smooth - boolean (True: antialias on, False: antialias is off)
-
-=cut
-*/
-
-static
-int
-i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, i_img_dim cords[6], double points, char const* txt, size_t len, int smooth, int utf8 ) {
- int inst;
- i_img_dim width, height;
- TT_Raster_Map small_bit;
-
- /* find or install an instance */
- if ( (inst=i_tt_get_instance(handle,points,smooth)) < 0) {
- mm_log((1,"i_tt_rasterize: get instance failed\n"));
- return 0;
- }
-
- /* calculate bounding box */
- if (!i_tt_bbox_inst( handle, inst, txt, len, cords, utf8 ))
- return 0;
-
-
- width = cords[2]-cords[0];
- height = cords[5]-cords[4];
-
- mm_log((1,"i_tt_rasterize: width=%" i_DF ", height=%" i_DF "\n",
- i_DFc(width), i_DFc(height) ));
-
- i_tt_init_raster_map ( bit, width, height, smooth );
- i_tt_clear_raster_map( bit );
- if ( smooth ) i_tt_init_raster_map( &small_bit, handle->instanceh[inst].imetrics.x_ppem + 32, height, smooth );
-
- if (!i_tt_render_all_glyphs( handle, inst, bit, &small_bit, cords, txt, len,
- smooth, utf8 )) {
- if ( smooth )
- i_tt_done_raster_map( &small_bit );
- return 0;
- }
-
- if ( smooth ) i_tt_done_raster_map( &small_bit );
- return 1;
-}
-
-
-
-/*
- * Exported text rendering interfaces
- */
-
-
-/*
-=item i_tt_cp(handle, im, xb, yb, channel, points, txt, len, smooth, utf8)
-
-Interface to text rendering into a single channel in an image
-
- handle - pointer to font handle
- im - image to render text on to
- xb, yb - coordinates, left edge and baseline
- channel - channel to render into
- points - font size to use
- txt - string to render
- len - length of the string to render
- smooth - boolean (True: antialias on, False: antialias is off)
-
-=cut
-*/
-
-undef_int
-i_tt_cp( TT_Fonthandle *handle, i_img *im, i_img_dim xb, i_img_dim yb, int channel, double points, char const* txt, size_t len, int smooth, int utf8, int align ) {
-
- i_img_dim cords[BOUNDING_BOX_COUNT];
- i_img_dim ascent, st_offset, y;
- TT_Raster_Map bit;
-
- i_clear_error();
- if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0;
-
- ascent=cords[BBOX_ASCENT];
- st_offset=cords[BBOX_NEG_WIDTH];
- y = align ? yb-ascent : yb;
-
- i_tt_dump_raster_map_channel( im, &bit, xb-st_offset , y, channel, smooth );
- i_tt_done_raster_map( &bit );
-
- return 1;
-}
-
-
-/*
-=item i_tt_text(handle, im, xb, yb, cl, points, txt, len, smooth, utf8)
-
-Interface to text rendering in a single color onto an image
-
- handle - pointer to font handle
- im - image to render text on to
- xb, yb - coordinates, left edge and baseline
- cl - color to use for text
- points - font size to use
- txt - string to render
- len - length of the string to render
- smooth - boolean (True: antialias on, False: antialias is off)
-
-=cut
-*/
-
-undef_int
-i_tt_text( TT_Fonthandle *handle, i_img *im, i_img_dim xb, i_img_dim yb, const i_color *cl, double points, char const* txt, size_t len, int smooth, int utf8, int align) {
- i_img_dim cords[BOUNDING_BOX_COUNT];
- i_img_dim ascent, st_offset, y;
- TT_Raster_Map bit;
-
- i_clear_error();
-
- if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0;
-
- ascent=cords[BBOX_ASCENT];
- st_offset=cords[BBOX_NEG_WIDTH];
- y = align ? yb-ascent : yb;
-
- i_tt_dump_raster_map2( im, &bit, xb+st_offset, y, cl, smooth );
- i_tt_done_raster_map( &bit );
-
- return 1;
-}
-
-
-/*
-=item i_tt_bbox_inst(handle, inst, txt, len, cords, utf8)
-
-Function to get texts bounding boxes given the instance of the font (internal)
-
- handle - pointer to font handle
- inst - font instance
- txt - string to measure
- len - length of the string to render
- cords - the bounding box (modified in place)
-
-=cut
-*/
-
-static
-undef_int
-i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, size_t len, i_img_dim cords[BOUNDING_BOX_COUNT], int utf8 ) {
- int upm, casc, cdesc, first;
-
- int start = 0;
- i_img_dim width = 0;
- int gdescent = 0;
- int gascent = 0;
- int descent = 0;
- int ascent = 0;
- int rightb = 0;
-
- unsigned long j;
- unsigned char *ustr;
- ustr=(unsigned char*)txt;
-
- mm_log((1,"i_tt_box_inst(handle %p,inst %d,txt '%.*s', len %ld, utf8 %d)\n",
- handle, inst, (int)len, txt, (long)len, utf8));
-
- upm = handle->properties.header->Units_Per_EM;
- gascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem + upm - 1) / upm;
- gdescent = ( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem - upm + 1) / upm;
-
- width = 0;
- start = 0;
-
- mm_log((1, "i_tt_box_inst: gascent=%d gdescent=%d\n", gascent, gdescent));
-
- first=1;
- while (len) {
- if (utf8) {
- j = i_utf8_advance(&txt, &len);
- if (j == ~0UL) {
- i_push_error(0, "invalid UTF8 character");
- return 0;
- }
- }
- else {
- j = (unsigned char)*txt++;
- --len;
- }
- if ( i_tt_get_glyph(handle,inst,j) ) {
- TT_Glyph_Metrics *gm = handle->instanceh[inst].gmetrics + TT_HASH(j);
- width += gm->advance / 64;
- casc = (gm->bbox.yMax+63) / 64;
- cdesc = (gm->bbox.yMin-63) / 64;
-
- mm_log((1, "i_tt_box_inst: glyph='%c' casc=%d cdesc=%d\n",
- (int)((j >= ' ' && j <= '~') ? j : '.'), casc, cdesc));
-
- if (first) {
- start = gm->bbox.xMin / 64;
- ascent = (gm->bbox.yMax+63) / 64;
- descent = (gm->bbox.yMin-63) / 64;
- first = 0;
- }
- if (!len) { /* if at end of string */
- /* the right-side bearing - in case the right-side of a
- character goes past the right of the advance width,
- as is common for italic fonts
- */
- rightb = gm->advance - gm->bearingX
- - (gm->bbox.xMax - gm->bbox.xMin);
- /* fprintf(stderr, "font info last: %d %d %d %d\n",
- gm->bbox.xMax, gm->bbox.xMin, gm->advance, rightb); */
- }
-
- ascent = (ascent > casc ? ascent : casc );
- descent = (descent < cdesc ? descent : cdesc);
- }
- }
-
- cords[BBOX_NEG_WIDTH]=start;
- cords[BBOX_GLOBAL_DESCENT]=gdescent;
- cords[BBOX_POS_WIDTH]=width;
- if (rightb < 0)
- cords[BBOX_POS_WIDTH] -= rightb / 64;
- cords[BBOX_GLOBAL_ASCENT]=gascent;
- cords[BBOX_DESCENT]=descent;
- cords[BBOX_ASCENT]=ascent;
- cords[BBOX_ADVANCE_WIDTH] = width;
- cords[BBOX_RIGHT_BEARING] = rightb / 64;
-
- return BBOX_RIGHT_BEARING + 1;
-}
-
-
-/*
-=item i_tt_bbox(handle, points, txt, len, cords, utf8)
-
-Interface to get a strings bounding box
-
- handle - pointer to font handle
- points - font size to use
- txt - string to render
- len - length of the string to render
- cords - the bounding box (modified in place)
-
-=cut
-*/
-
-undef_int
-i_tt_bbox( TT_Fonthandle *handle, double points,const char *txt,size_t len,i_img_dim cords[6], int utf8) {
- int inst;
-
- i_clear_error();
- mm_log((1,"i_tt_box(handle %p,points %f,txt '%.*s', len %ld, utf8 %d)\n",
- handle, points, (int)len, txt, (long)len, utf8));
-
- if ( (inst=i_tt_get_instance(handle,points,-1)) < 0) {
- i_push_errorf(0, "i_tt_get_instance(%g)", points);
- mm_log((1,"i_tt_text: get instance failed\n"));
- return 0;
- }
-
- return i_tt_bbox_inst(handle, inst, txt, len, cords, utf8);
-}
-
-/*
-=item i_tt_face_name(handle, name_buf, name_buf_size)
-
-Retrieve's the font's postscript name.
-
-This is complicated by the need to handle encodings and so on.
-
-=cut
- */
-size_t
-i_tt_face_name(TT_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
- TT_Face_Properties props;
- int name_count;
- int i;
- TT_UShort platform_id, encoding_id, lang_id, name_id;
- TT_UShort name_len;
- TT_String *name;
- int want_index = -1; /* an acceptable but not perfect name */
- int score = 0;
-
- i_clear_error();
-
- TT_Get_Face_Properties(handle->face, &props);
- name_count = props.num_Names;
- for (i = 0; i < name_count; ++i) {
- TT_Get_Name_ID(handle->face, i, &platform_id, &encoding_id, &lang_id,
- &name_id);
-
- TT_Get_Name_String(handle->face, i, &name, &name_len);
-
- if (platform_id != TT_PLATFORM_APPLE_UNICODE && name_len
- && name_id == TT_NAME_ID_PS_NAME) {
- int might_want_index = -1;
- int might_score = 0;
- if ((platform_id == TT_PLATFORM_MACINTOSH && encoding_id == TT_MAC_ID_ROMAN)
- ||
- (platform_id == TT_PLATFORM_MICROSOFT && encoding_id == TT_MS_LANGID_ENGLISH_UNITED_STATES)) {
- /* exactly what we want */
- want_index = i;
- break;
- }
-
- if (platform_id == TT_PLATFORM_MICROSOFT
- && (encoding_id & 0xFF) == TT_MS_LANGID_ENGLISH_GENERAL) {
- /* any english is good */
- might_want_index = i;
- might_score = 9;
- }
- /* there might be something in between */
- else {
- /* anything non-unicode is better than nothing */
- might_want_index = i;
- might_score = 1;
- }
- if (might_score > score) {
- score = might_score;
- want_index = might_want_index;
- }
- }
- }
-
- if (want_index != -1) {
- TT_Get_Name_String(handle->face, want_index, &name, &name_len);
-
- strncpy(name_buf, name, name_buf_size);
- name_buf[name_buf_size-1] = '\0';
-
- return strlen(name) + 1;
- }
- else {
- i_push_error(0, "no face name present");
- return 0;
- }
-}
-
-void i_tt_dump_names(TT_Fonthandle *handle) {
- TT_Face_Properties props;
- int name_count;
- int i;
- TT_UShort platform_id, encoding_id, lang_id, name_id;
- TT_UShort name_len;
- TT_String *name;
-
- TT_Get_Face_Properties(handle->face, &props);
- name_count = props.num_Names;
- for (i = 0; i < name_count; ++i) {
- TT_Get_Name_ID(handle->face, i, &platform_id, &encoding_id, &lang_id,
- &name_id);
- TT_Get_Name_String(handle->face, i, &name, &name_len);
-
- printf("# %d: plat %d enc %d lang %d name %d value ", i, platform_id,
- encoding_id, lang_id, name_id);
- if (platform_id == TT_PLATFORM_APPLE_UNICODE) {
- printf("(unicode)\n");
- }
- else {
- printf("'%s'\n", name);
- }
- }
- fflush(stdout);
-}
-
-size_t
-i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf,
- size_t name_buf_size) {
-#ifdef FTXPOST
- TT_Error rc;
- TT_String *psname;
- TT_UShort index;
-
- i_clear_error();
-
- if (!handle->loaded_names) {
- TT_Post post;
- mm_log((1, "Loading PS Names"));
- handle->load_cond = TT_Load_PS_Names(handle->face, &post);
- ++handle->loaded_names;
- }
-
- if (handle->load_cond) {
- i_push_errorf(handle->load_cond, "error loading names (%#x)",
- (unsigned)handle->load_cond);
- return 0;
- }
-
- index = TT_Char_Index(handle->char_map, ch);
- if (!index) {
- i_push_error(0, "no such character");
- return 0;
- }
-
- rc = TT_Get_PS_Name(handle->face, index, &psname);
-
- if (rc) {
- i_push_error(rc, "error getting name");
- return 0;
- }
-
- strncpy(name_buf, psname, name_buf_size);
- name_buf[name_buf_size-1] = '\0';
-
- return strlen(psname) + 1;
-#else
- mm_log((1, "FTXPOST extension not enabled\n"));
- i_clear_error();
- i_push_error(0, "Use of FTXPOST extension disabled");
-
- return 0;
-#endif
-}
-
-/*
-=item i_tt_push_error(code)
-
-Push an error message and code onto the Imager error stack.
-
-=cut
-*/
-static void
-i_tt_push_error(TT_Error rc) {
-#ifdef FTXERR18
- TT_String const *msg = TT_ErrToString18(rc);
-
- i_push_error(rc, msg);
-#else
- i_push_errorf(rc, "Error code 0x%04x", (unsigned)rc);
-#endif
-}
-
-
-/*
-=back
-
-=head1 AUTHOR
-
-Arnar M. Hrafnkelsson <addi@umich.edu>
-
-=head1 SEE ALSO
-
-Imager(3)
-
-=cut
-*/
-#define IMAGER_NO_CONTEXT
#include "imager.h"
#include <math.h>
double res[MAXCHANNELS];
i_img *timg;
int radius, diameter;
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_gaussian(im %p, stdev %.2f)\n",im,stddev));
+ mm_log((1,"i_gaussian(im %p, stdev %.2f)\n",im,stddev));
i_clear_error();
if (stddev <= 0) {
-#define IMAGER_NO_CONTEXT
#include "imageri.h"
#include <stdlib.h>
size_t bytes = count_y * sizeof(i_int_hline_entry *);
if (bytes / count_y != sizeof(i_int_hline_entry *)) {
- dIMCTX;
- im_fatal(aIMCTX, 3, "integer overflow calculating memory allocation\n");
+ i_fatal(3, "integer overflow calculating memory allocation\n");
}
hlines->start_y = start_y;
i_img_dim x_limit = x + width;
if (width < 0) {
- dIMCTX;
- im_fatal(aIMCTX, 3, "negative width %d passed to i_int_hlines_add\n", width);
+ i_fatal(3, "negative width %d passed to i_int_hlines_add\n", width);
}
/* just return if out of range */
-#define IMAGER_NO_CONTEXT
-
#include "imager.h"
#include "imageri.h"
i_color *c;
c = i_color_new(red, green, blue, alpha);
ICL_DESTROY(c);
- i = i_img_8_new();
+ i = i_img_new();
i_img_destroy(i);
// and much more
=cut
*/
-im_context_t (*im_get_context)(void) = NULL;
-
#define XAXIS 0
#define YAXIS 1
#define XYAXIS 2
void i_linker_bug_fake(void) { ceil(1); }
/*
-=item im_img_alloc(aIMCTX)
-X<im_img_alloc API>X<i_img_alloc API>
+=item i_img_alloc()
=category Image Implementation
-=synopsis i_img *im = im_img_alloc(aIMCTX);
-=synopsis i_img *im = i_img_alloc();
Allocates a new i_img structure.
*/
i_img *
-im_img_alloc(pIMCTX) {
+i_img_alloc(void) {
return mymalloc(sizeof(i_img));
}
/*
-=item im_img_init(aIMCTX, image)
-X<im_img_init API>X<i_img_init API>
+=item i_img_init(C<img>)
=category Image Implementation
-=synopsis im_img_init(aIMCTX, im);
-=synopsis i_img_init(im);
Imager internal initialization of images.
-See L</im_img_alloc(aIMCTX)> for more information.
+Currently this does very little, in the future it may be used to
+support threads, or color profiles.
=cut
*/
void
-im_img_init(pIMCTX, i_img *img) {
+i_img_init(i_img *img) {
img->im_data = NULL;
- img->context = aIMCTX;
- im_context_refinc(aIMCTX, "img_init");
}
/*
i_color *
ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
i_color *cl = NULL;
- dIMCTX;
- im_log((aIMCTX,1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
+ mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
- if ( (cl=mymalloc(sizeof(i_color))) == NULL) im_fatal(aIMCTX, 2,"malloc() error\n");
+ if ( (cl=mymalloc(sizeof(i_color))) == NULL) i_fatal(2,"malloc() error\n");
cl->rgba.r = r;
cl->rgba.g = g;
cl->rgba.b = b;
cl->rgba.a = a;
- im_log((aIMCTX,1,"(%p) <- ICL_new_internal\n",cl));
+ mm_log((1,"(%p) <- ICL_new_internal\n",cl));
return cl;
}
i_color *
ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
- dIMCTX;
- im_log((aIMCTX,1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
+ mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
if (cl == NULL)
if ( (cl=mymalloc(sizeof(i_color))) == NULL)
- im_fatal(aIMCTX, 2,"malloc() error\n");
+ i_fatal(2,"malloc() error\n");
cl->rgba.r=r;
cl->rgba.g=g;
cl->rgba.b=b;
cl->rgba.a=a;
- im_log((aIMCTX,1,"(%p) <- ICL_set_internal\n",cl));
+ mm_log((1,"(%p) <- ICL_set_internal\n",cl));
return cl;
}
void
ICL_info(i_color const *cl) {
- dIMCTX;
- im_log((aIMCTX, 1,"i_color_info(cl* %p)\n",cl));
- im_log((aIMCTX, 1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
+ mm_log((1,"i_color_info(cl* %p)\n",cl));
+ mm_log((1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
}
/*
void
ICL_DESTROY(i_color *cl) {
- dIMCTX;
- im_log((aIMCTX, 1,"ICL_DESTROY(cl* %p)\n",cl));
+ mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
myfree(cl);
}
*/
i_fcolor *i_fcolor_new(double r, double g, double b, double a) {
i_fcolor *cl = NULL;
- dIMCTX;
- im_log((aIMCTX, 1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
+ mm_log((1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
- if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) im_fatal(aIMCTX, 2,"malloc() error\n");
+ if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) i_fatal(2,"malloc() error\n");
cl->rgba.r = r;
cl->rgba.g = g;
cl->rgba.b = b;
cl->rgba.a = a;
- im_log((aIMCTX, 1,"(%p) <- i_fcolor_new\n",cl));
+ mm_log((1,"(%p) <- i_fcolor_new\n",cl));
return cl;
}
void
i_img_exorcise(i_img *im) {
- dIMCTXim(im);
- im_log((aIMCTX,1,"i_img_exorcise(im* %p)\n",im));
+ mm_log((1,"i_img_exorcise(im* %p)\n",im));
i_tags_destroy(&im->tags);
if (im->i_f_destroy)
(im->i_f_destroy)(im);
void
i_img_destroy(i_img *im) {
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_img_destroy(im %p)\n",im));
+ mm_log((1,"i_img_destroy(im %p)\n",im));
i_img_exorcise(im);
if (im) { myfree(im); }
- im_context_refdec(aIMCTX, "img_destroy");
}
/*
void
i_img_info(i_img *im, i_img_dim *info) {
- dIMCTXim(im);
- im_log((aIMCTX,1,"i_img_info(im %p)\n",im));
+ mm_log((1,"i_img_info(im %p)\n",im));
if (im != NULL) {
- im_log((aIMCTX,1,"i_img_info: xsize=%" i_DF " ysize=%" i_DF " channels=%d "
+ mm_log((1,"i_img_info: xsize=%" i_DF " ysize=%" i_DF " channels=%d "
"mask=%ud\n",
i_DFc(im->xsize), i_DFc(im->ysize), im->channels,im->ch_mask));
- im_log((aIMCTX,1,"i_img_info: idata=%p\n",im->idata));
+ mm_log((1,"i_img_info: idata=%p\n",im->idata));
info[0] = im->xsize;
info[1] = im->ysize;
info[2] = im->channels;
i_color pv;
i_img_dim x,y,t,ttx,tty,tt;
int ch;
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_copyto_trans(im* %p,src %p, p1(" i_DFp "), p2(" i_DFp "), "
+ mm_log((1,"i_copyto_trans(im* %p,src %p, p1(" i_DFp "), p2(" i_DFp "), "
"to(" i_DFp "), trans* %p)\n",
im, src, i_DFcp(x1, y1), i_DFcp(x2, y2), i_DFcp(tx, ty), trans));
i_img *
i_copy(i_img *src) {
i_img_dim y, y1, x1;
- dIMCTXim(src);
i_img *im = i_sametype(src, src->xsize, src->ysize);
- im_log((aIMCTX,1,"i_copy(src %p)\n", src));
+ mm_log((1,"i_copy(src %p)\n", src));
if (!im)
return NULL;
i_img *new_img;
int has_alpha = i_img_has_alpha(im);
int color_chans = i_img_color_channels(im);
- dIMCTXim(im);
i_clear_error();
- im_log((aIMCTX, 1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
+ mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
if (Axis == XAXIS) {
hsize = (i_img_dim)(0.5 + im->xsize * Value);
iEnd = hsize;
}
- new_img = i_img_8_new(hsize, vsize, im->channels);
+ new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
if (!new_img) {
i_push_error(0, "cannot create output image");
return NULL;
myfree(l0);
myfree(l1);
- im_log((aIMCTX, 1,"(%p) <- i_scaleaxis\n", new_img));
+ mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
return new_img;
}
i_img_dim nxsize,nysize,nx,ny;
i_img *new_img;
i_color val;
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_scale_nn(im %p,scx %.2f,scy %.2f)\n",im,scx,scy));
+ mm_log((1,"i_scale_nn(im %p,scx %.2f,scy %.2f)\n",im,scx,scy));
nxsize = (i_img_dim) ((double) im->xsize * scx);
if (nxsize < 1) {
i_ppix(new_img,nx,ny,&val);
}
- im_log((aIMCTX, 1,"(%p) <- i_scale_nn\n",new_img));
+ mm_log((1,"(%p) <- i_scale_nn\n",new_img));
return new_img;
}
=cut
*/
-i_img *
-i_sametype(i_img *src, i_img_dim xsize, i_img_dim ysize) {
- dIMCTXim(src);
-
+i_img *i_sametype(i_img *src, i_img_dim xsize, i_img_dim ysize) {
if (src->type == i_direct_type) {
if (src->bits == 8) {
return i_img_empty_ch(NULL, xsize, ysize, src->channels);
=cut
*/
-i_img *
-i_sametype_chans(i_img *src, i_img_dim xsize, i_img_dim ysize, int channels) {
- dIMCTXim(src);
-
+i_img *i_sametype_chans(i_img *src, i_img_dim xsize, i_img_dim ysize, int channels) {
if (src->bits == 8) {
return i_img_empty_ch(NULL, xsize, ysize, channels);
}
i_img_dim nxsize,nysize,nx,ny;
i_img *new_img;
i_color val;
- dIMCTXim(im);
- im_log((aIMCTX, 1,"i_transform(im %p, opx %p, opxl %d, opy %p, opyl %d, parm %p, parmlen %d)\n",im,opx,opxl,opy,opyl,parm,parmlen));
+ mm_log((1,"i_transform(im %p, opx %p, opxl %d, opy %p, opyl %d, parm %p, parmlen %d)\n",im,opx,opxl,opy,opyl,parm,parmlen));
nxsize = im->xsize;
nysize = im->ysize ;
i_ppix(new_img,nx,ny,&val);
}
- im_log((aIMCTX, 1,"(%p) <- i_transform\n",new_img));
+ mm_log((1,"(%p) <- i_transform\n",new_img));
return new_img;
}
int ch, chb;
float tdiff;
i_color val1,val2;
- dIMCTXim(im1);
- im_log((aIMCTX, 1,"i_img_diff(im1 %p,im2 %p)\n",im1,im2));
+ mm_log((1,"i_img_diff(im1 %p,im2 %p)\n",im1,im2));
xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
- im_log((aIMCTX, 1,"i_img_diff: b=(" i_DFp ") chb=%d\n",
+ mm_log((1,"i_img_diff: b=(" i_DFp ") chb=%d\n",
i_DFcp(xb,yb), chb));
tdiff=0;
for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
}
- im_log((aIMCTX, 1,"i_img_diff <- (%.2f)\n",tdiff));
+ mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
return tdiff;
}
int ch, chb;
double tdiff;
i_fcolor val1,val2;
- dIMCTXim(im1);
- im_log((aIMCTX, 1,"i_img_diffd(im1 %p,im2 %p)\n",im1,im2));
+ mm_log((1,"i_img_diffd(im1 %p,im2 %p)\n",im1,im2));
xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
- im_log((aIMCTX, 1,"i_img_diffd: b(" i_DFp ") chb=%d\n",
+ mm_log((1,"i_img_diffd: b(" i_DFp ") chb=%d\n",
i_DFcp(xb, yb), chb));
tdiff=0;
tdiff += sdiff * sdiff;
}
}
- im_log((aIMCTX, 1,"i_img_diffd <- (%.2f)\n",tdiff));
+ mm_log((1,"i_img_diffd <- (%.2f)\n",tdiff));
return tdiff;
}
i_img_dim x,y,xb,yb;
int ch, chb;
i_fcolor val1,val2;
- dIMCTXim(im1);
if (what == NULL)
what = "(null)";
- im_log((aIMCTX,1,"i_img_samef(im1 %p,im2 %p, epsilon %g, what '%s')\n", im1, im2, epsilon, what));
+ mm_log((1,"i_img_samef(im1 %p,im2 %p, epsilon %g, what '%s')\n", im1, im2, epsilon, what));
xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
- im_log((aIMCTX, 1,"i_img_samef: b(" i_DFp ") chb=%d\n",
+ mm_log((1,"i_img_samef: b(" i_DFp ") chb=%d\n",
i_DFcp(xb, yb), chb));
for(y = 0; y < yb; y++) {
for(ch = 0; ch < chb; ch++) {
double sdiff = val1.channel[ch] - val2.channel[ch];
if (fabs(sdiff) > epsilon) {
- im_log((aIMCTX, 1,"i_img_samef <- different %g @(" i_DFp ")\n",
+ mm_log((1,"i_img_samef <- different %g @(" i_DFp ")\n",
sdiff, i_DFcp(x, y)));
return 0;
}
}
}
}
- im_log((aIMCTX, 1,"i_img_samef <- same\n"));
+ mm_log((1,"i_img_samef <- same\n"));
return 1;
}
int ch,c;
i_img *new_img,*new_img2;
i_color val1,val2,dval1,dval2;
- dIMCTXim(im);
mx=im->xsize;
my=im->ysize;
i_img_dim
i_gsamp_bits_fb(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps,
const int *chans, int chan_count, int bits) {
- dIMCTXim(im);
-
if (bits < 1 || bits > 32) {
i_push_error(0, "Invalid bits, must be 1..32");
return -1;
/* make sure we have good channel numbers */
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return -1;
}
}
#define _IMAGE_H_
#include "imconfig.h"
-#include "immacros.h"
#include "imio.h"
#include "iolayer.h"
+#include "log.h"
#include "stackmach.h"
+
#ifndef _MSC_VER
#include <unistd.h>
#endif
extern void i_rgb_to_hsv(i_color *color);
extern void i_hsv_to_rgb(i_color *color);
-i_img *im_img_8_new(pIMCTX, i_img_dim x,i_img_dim y,int ch);
-#define i_img_empty(im, x, y) i_img_empty_ch((im), (x), (y), 3)
-i_img *im_img_empty_ch(pIMCTX, i_img *im,i_img_dim x,i_img_dim y,int ch);
-#define i_img_empty_ch(im, x, y, ch) im_img_empty_ch(aIMCTX, (im), (x), (y), (ch))
+i_img *i_img_8_new(i_img_dim x,i_img_dim y,int ch);
+i_img *i_img_new( void );
+i_img *i_img_empty(i_img *im,i_img_dim x,i_img_dim y);
+i_img *i_img_empty_ch(i_img *im,i_img_dim x,i_img_dim y,int ch);
void i_img_exorcise(i_img *im);
void i_img_destroy(i_img *im);
-i_img *im_img_alloc(pIMCTX);
-void im_img_init(pIMCTX, i_img *im);
+i_img *i_img_alloc(void);
+void i_img_init(i_img *im);
void i_img_info(i_img *im,i_img_dim *info);
extern i_img *i_sametype(i_img *im, i_img_dim xsize, i_img_dim ysize);
extern i_img *i_sametype_chans(i_img *im, i_img_dim xsize, i_img_dim ysize, int channels);
+i_img *i_img_pal_new(i_img_dim x, i_img_dim y, int ch, int maxpal);
+
/* Image feature settings */
void i_img_setmask (i_img *im,int ch_mask);
/* Base functions */
-extern int (i_ppix)(i_img *im,i_img_dim x,i_img_dim y, const i_color *val);
-extern int (i_gpix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val);
-extern int (i_ppixf)(i_img *im,i_img_dim x,i_img_dim y, const i_fcolor *val);
-extern int (i_gpixf)(i_img *im,i_img_dim x,i_img_dim y,i_fcolor *val);
-
-extern i_img_dim (i_plin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
- const i_color *vals);
-extern i_img_dim (i_glin)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
- i_color *vals);
-extern i_img_dim (i_plinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
- const i_fcolor *vals);
-extern i_img_dim (i_glinf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
- i_fcolor *vals);
-extern i_img_dim (i_gsamp)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
- i_sample_t *samp, const int *chans, int chan_count);
-extern i_img_dim
-(i_gsampf)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp,
- const int *chans, int chan_count);
-extern i_img_dim
-(i_gpal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_palidx *vals);
-extern i_img_dim
-(i_ppal)(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_palidx *vals);
-extern int (i_addcolors)(i_img *im, const i_color *colors, int count);
-extern int (i_getcolors)(i_img *im, int i, i_color *, int count);
-extern int (i_colorcount)(i_img *im);
-extern int (i_maxcolors)(i_img *im);
-extern int (i_findcolor)(i_img *im, const i_color *color, i_palidx *entry);
-extern int (i_setcolors)(i_img *im, int index, const i_color *colors,
+extern int i_ppix(i_img *im,i_img_dim x,i_img_dim y, const i_color *val);
+extern int i_gpix(i_img *im,i_img_dim x,i_img_dim y,i_color *val);
+extern int i_ppixf(i_img *im,i_img_dim x,i_img_dim y, const i_fcolor *val);
+extern int i_gpixf(i_img *im,i_img_dim x,i_img_dim y,i_fcolor *val);
+
+#define i_ppix(im, x, y, val) (((im)->i_f_ppix)((im), (x), (y), (val)))
+#define i_gpix(im, x, y, val) (((im)->i_f_gpix)((im), (x), (y), (val)))
+#define i_ppixf(im, x, y, val) (((im)->i_f_ppixf)((im), (x), (y), (val)))
+#define i_gpixf(im, x, y, val) (((im)->i_f_gpixf)((im), (x), (y), (val)))
+
+extern i_img_dim i_plin(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals);
+extern i_img_dim i_glin(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
+extern i_img_dim i_plinf(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals);
+extern i_img_dim i_glinf(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
+extern i_img_dim i_gsamp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samp,
+ const int *chans, int chan_count);
+extern i_img_dim i_gsampf(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp,
+ const int *chans, int chan_count);
+extern i_img_dim i_gpal(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, i_palidx *vals);
+extern i_img_dim i_ppal(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, const i_palidx *vals);
+extern int i_addcolors(i_img *im, const i_color *colors, int count);
+extern int i_getcolors(i_img *im, int i, i_color *, int count);
+extern int i_colorcount(i_img *im);
+extern int i_maxcolors(i_img *im);
+extern int i_findcolor(i_img *im, const i_color *color, i_palidx *entry);
+extern int i_setcolors(i_img *im, int index, const i_color *colors,
int count);
+#define i_plin(im, l, r, y, val) (((im)->i_f_plin)(im, l, r, y, val))
+#define i_glin(im, l, r, y, val) (((im)->i_f_glin)(im, l, r, y, val))
+#define i_plinf(im, l, r, y, val) (((im)->i_f_plinf)(im, l, r, y, val))
+#define i_glinf(im, l, r, y, val) (((im)->i_f_glinf)(im, l, r, y, val))
+
+#define i_gsamp(im, l, r, y, samps, chans, count) \
+ (((im)->i_f_gsamp)((im), (l), (r), (y), (samps), (chans), (count)))
+#define i_gsampf(im, l, r, y, samps, chans, count) \
+ (((im)->i_f_gsampf)((im), (l), (r), (y), (samps), (chans), (count)))
+
+#define i_gsamp_bits(im, l, r, y, samps, chans, count, bits) \
+ (((im)->i_f_gsamp_bits) ? ((im)->i_f_gsamp_bits)((im), (l), (r), (y), (samps), (chans), (count), (bits)) : -1)
+#define i_psamp_bits(im, l, r, y, samps, chans, count, bits) \
+ (((im)->i_f_psamp_bits) ? ((im)->i_f_psamp_bits)((im), (l), (r), (y), (samps), (chans), (count), (bits)) : -1)
+
+#define i_findcolor(im, color, entry) \
+ (((im)->i_f_findcolor) ? ((im)->i_f_findcolor)((im), (color), (entry)) : 0)
+
+#define i_gpal(im, l, r, y, vals) \
+ (((im)->i_f_gpal) ? ((im)->i_f_gpal)((im), (l), (r), (y), (vals)) : 0)
+#define i_ppal(im, l, r, y, vals) \
+ (((im)->i_f_ppal) ? ((im)->i_f_ppal)((im), (l), (r), (y), (vals)) : 0)
+#define i_addcolors(im, colors, count) \
+ (((im)->i_f_addcolors) ? ((im)->i_f_addcolors)((im), (colors), (count)) : -1)
+#define i_getcolors(im, index, color, count) \
+ (((im)->i_f_getcolors) ? \
+ ((im)->i_f_getcolors)((im), (index), (color), (count)) : 0)
+#define i_setcolors(im, index, color, count) \
+ (((im)->i_f_setcolors) ? \
+ ((im)->i_f_setcolors)((im), (index), (color), (count)) : 0)
+#define i_colorcount(im) \
+ (((im)->i_f_colorcount) ? ((im)->i_f_colorcount)(im) : -1)
+#define i_maxcolors(im) \
+ (((im)->i_f_maxcolors) ? ((im)->i_f_maxcolors)(im) : -1)
+#define i_findcolor(im, color, entry) \
+ (((im)->i_f_findcolor) ? ((im)->i_f_findcolor)((im), (color), (entry)) : 0)
+
+#define i_img_virtual(im) ((im)->virtual)
+#define i_img_type(im) ((im)->type)
+#define i_img_bits(im) ((im)->bits)
extern i_fill_t *i_new_fill_solidf(const i_fcolor *c, int combine);
extern i_fill_t *i_new_fill_solid(const i_color *c, int combine);
/* font routines */
-#ifdef HAVE_LIBTT
+undef_int i_init_fonts( int t1log );
-extern void i_tt_start(void);
+#ifdef HAVE_LIBTT
TT_Fonthandle* i_tt_new(const char *fontname);
void i_tt_destroy( TT_Fonthandle *handle );
extern i_palidx *i_quant_translate(i_quantize *quant, i_img *img);
extern void i_quant_transparent(i_quantize *quant, i_palidx *indices, i_img *img, i_palidx trans_index);
-i_img *im_img_pal_new(pIMCTX, i_img_dim x, i_img_dim y, int ch, int maxpal);
-
+extern i_img *i_img_pal_new(i_img_dim x, i_img_dim y, int channels, int maxpal);
extern i_img *i_img_to_pal(i_img *src, i_quantize *quant);
extern i_img *i_img_to_rgb(i_img *src);
extern i_img *i_img_masked_new(i_img *targ, i_img *mask, i_img_dim x, i_img_dim y,
i_img_dim w, i_img_dim h);
-extern i_img *im_img_16_new(pIMCTX, i_img_dim x, i_img_dim y, int ch);
+extern i_img *i_img_16_new(i_img_dim x, i_img_dim y, int ch);
extern i_img *i_img_to_rgb16(i_img *im);
-extern i_img *im_img_double_new(pIMCTX, i_img_dim x, i_img_dim y, int ch);
+extern i_img *i_img_double_new(i_img_dim x, i_img_dim y, int ch);
extern i_img *i_img_to_drgb(i_img *im);
extern int i_img_is_monochrome(i_img *im, int *zero_is_white);
void malloc_state( void );
+/* this is sort of obsolete now */
+
+typedef struct {
+ undef_int (*i_has_format)(char *frmt);
+ i_color*(*ICL_set)(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a);
+ void (*ICL_info)(const i_color *cl);
+
+ i_img*(*i_img_new)( void );
+ i_img*(*i_img_empty)(i_img *im,i_img_dim x,i_img_dim y);
+ i_img*(*i_img_empty_ch)(i_img *im,i_img_dim x,i_img_dim y,int ch);
+ void(*i_img_exorcise)(i_img *im);
+
+ void(*i_img_info)(i_img *im,i_img_dim *info);
+
+ void(*i_img_setmask)(i_img *im,int ch_mask);
+ int (*i_img_getmask)(i_img *im);
+
+ /*
+ int (*i_ppix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val);
+ int (*i_gpix)(i_img *im,i_img_dim x,i_img_dim y,i_color *val);
+ */
+ void(*i_box)(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val);
+ void(*i_line)(i_img *im,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,const i_color *val,int endp);
+ void(*i_arc)(i_img *im,i_img_dim x,i_img_dim y,double rad,double d1,double d2,const i_color *val);
+ void(*i_copyto)(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty);
+ void(*i_copyto_trans)(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty,const i_color *trans);
+ int(*i_rubthru)(i_img *im,i_img *src,i_img_dim tx,i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy);
+
+} symbol_table_t;
+
#include "imerror.h"
/* image tag processing */
/* image file limits */
extern int
-im_set_image_file_limits(im_context_t ctx, i_img_dim width, i_img_dim height, size_t bytes);
+i_set_image_file_limits(i_img_dim width, i_img_dim height, size_t bytes);
extern int
-im_get_image_file_limits(im_context_t ctx, i_img_dim *width, i_img_dim *height, size_t *bytes);
+i_get_image_file_limits(i_img_dim *width, i_img_dim *height, size_t *bytes);
extern int
-im_int_check_image_file_limits(im_context_t ctx, i_img_dim width, i_img_dim height, int channels, size_t sample_size);
+i_int_check_image_file_limits(i_img_dim width, i_img_dim height, int channels, size_t sample_size);
/* memory allocation */
void* mymalloc(size_t size);
#endif /* IMAGER_MALLOC_DEBUG */
#include "imrender.h"
+#include "immacros.h"
extern void
i_adapt_colors(int dest_channels, int src_channels, i_color *colors,
i_gsampf_bg(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samples,
int out_channels, i_fcolor const *bg);
-/* context object management */
-extern im_context_t im_context_new(void);
-extern void im_context_refinc(im_context_t ctx, const char *where);
-extern void im_context_refdec(im_context_t ctx, const char *where);
-extern im_context_t im_context_clone(im_context_t ctx, const char *where);
-extern im_slot_t im_context_slot_new(im_slot_destroy_t, const char *);
-extern void *im_context_slot_get(im_context_t ctx, im_slot_t slot);
-extern int im_context_slot_set(im_context_t ctx, im_slot_t slot, void *);
-
-extern im_context_t (*im_get_context)(void);
-
-/* mutex API */
-extern i_mutex_t i_mutex_new(void);
-extern void i_mutex_destroy(i_mutex_t m);
-extern void i_mutex_lock(i_mutex_t m);
-extern void i_mutex_unlock(i_mutex_t m);
-
#include "imio.h"
#endif
#define IMAGEI_H_
#include "imager.h"
-#include <stddef.h>
/* wrapper functions that implement the floating point sample version of a
function in terms of the 8-bit sample version
#define color_to_grey(col) ((col)->rgb.r * 0.222 + (col)->rgb.g * 0.707 + (col)->rgb.b * 0.071)
-#define IM_ERROR_COUNT 20
-typedef struct im_context_tag {
- int error_sp;
- size_t error_alloc[IM_ERROR_COUNT];
- i_errmsg error_stack[IM_ERROR_COUNT];
-#ifdef IMAGER_LOG
- int log_level;
- FILE *lg_file;
- const char *filename;
- int line;
-#endif
-
- /* file size limits */
- i_img_dim max_width, max_height;
- size_t max_bytes;
-
- /* per context storage */
- size_t slot_alloc;
- void **slots;
-
- ptrdiff_t refcount;
-} im_context_struct;
-
-#define DEF_BYTES_LIMIT 0x40000000
-
#endif
#define MAXCHANNELS 4
-typedef struct im_context_tag *im_context_t;
-
-typedef ptrdiff_t im_slot_t;
-typedef void (*im_slot_destroy_t)(void *);
-
/* used for palette indices in some internal code (which might be
exposed at some point
*/
i_f_psampf - implements psamp() for this image.
-=item *
-
-C<im_data> - image specific data internal to Imager.
-
-=item *
-
-C<context> - the Imager API context this image belongs to.
-
=back
=cut
i_f_psampf_t i_f_psampf;
void *im_data;
-
- /* 0.91 */
- im_context_t context;
};
/* ext_data for paletted images
ic_color
} i_combine_t;
-/*
-=item i_mutex_t
-X<i_mutex>
-=category mutex
-=synopsis i_mutex_t mutex;
-
-Opaque type for Imager's mutex API.
-
-=cut
- */
-typedef struct i_mutex_tag *i_mutex_t;
-
/*
describes an axis of a MM font.
Modelled on FT2's FT_MM_Axis.
#include "iolayert.h"
-/* error message information returned by im_errors() */
-
-typedef struct {
- char *msg;
- int code;
-} i_errmsg;
-
typedef struct i_render_tag i_render;
#ifdef IMAGER_FORMAT_ATTR
see error.c for documentation
the error information is currently global
*/
+typedef struct {
+ char *msg;
+ int code;
+} i_errmsg;
+
typedef void (*i_error_cb)(int code, char const *msg);
typedef void (*i_failed_cb)(i_errmsg *msgs);
extern i_error_cb i_set_error_cb(i_error_cb);
extern i_failed_cb i_set_failed_cb(i_failed_cb);
extern void i_set_argv0(char const *);
extern int i_set_errors_fatal(int new_fatal);
-extern i_errmsg *im_errors(pIMCTX);
+extern i_errmsg *i_errors(void);
-extern void im_push_error(pIMCTX, int code, char const *msg);
-#ifndef IMAGER_NO_CONTEXT
+extern void i_push_error(int code, char const *msg);
extern void i_push_errorf(int code, char const *fmt, ...) I_FORMAT_ATTR(2, 3);
-#endif
-extern void im_push_errorf(pIMCTX, int code, char const *fmt, ...) I_FORMAT_ATTR(3, 4);
-extern void im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list);
-extern void im_clear_error(pIMCTX);
+extern void i_push_errorvf(int code, char const *fmt, va_list);
+extern void i_clear_error(void);
extern int i_failed(int code, char const *msg);
#endif
#include "imager.h"
#include "imio.h"
-static im_context_t get_context(void);
-
/*
DON'T ADD CASTS TO THESE
*/
myfree_file_line,
myrealloc_file_line,
- im_img_8_new,
- im_img_16_new,
- im_img_double_new,
- im_img_pal_new,
+ i_img_8_new,
+ i_img_16_new,
+ i_img_double_new,
+ i_img_pal_new,
i_img_destroy,
i_sametype,
i_sametype_chans,
i_quant_translate,
i_quant_transparent,
- im_clear_error,
- im_push_error,
+ i_clear_error,
+ i_push_error,
i_push_errorf,
- im_push_errorvf,
+ i_push_errorvf,
i_tags_new,
i_tags_set,
i_rubthru,
/* IMAGER_API_LEVEL 2 functions */
- im_set_image_file_limits,
- im_get_image_file_limits,
- im_int_check_image_file_limits,
+ i_set_image_file_limits,
+ i_get_image_file_limits,
+ i_int_check_image_file_limits,
i_flood_fill_border,
i_flood_cfill_border,
i_loog,
/* IMAGER_API_LEVEL 4 functions */
- im_img_alloc,
- im_img_init,
+ i_img_alloc,
+ i_img_init,
/* IMAGER_API_LEVEL 5 functions */
i_img_is_monochrome,
i_io_close,
i_io_set_buffered,
i_io_gets,
- im_io_new_fd,
- im_io_new_bufchain,
- im_io_new_buffer,
- im_io_new_cb,
+ io_new_fd,
+ io_new_bufchain,
+ io_new_buffer,
+ io_new_cb,
io_slurp,
- io_glue_destroy,
-
- /* level 8 */
- get_context,
- im_push_errorf,
- im_lhead,
- im_loog,
- im_context_refinc,
- im_context_refdec,
- im_errors,
- i_mutex_new,
- i_mutex_destroy,
- i_mutex_lock,
- i_mutex_unlock,
- im_context_slot_new,
- im_context_slot_set,
- im_context_slot_get
+ io_glue_destroy
};
/* in general these functions aren't called by Imager internally, but
return i_setcolors(im, index, colors, count);
}
-/*
-=item im_get_context()
-
-Retrieve the context object for the current thread.
-
-Inside Imager itself this is just a function pointer, which the
-F<Imager.xs> BOOT handler initializes for use within perl. If you're
-taking the Imager code and embedding it elsewhere you need to
-initialize the C<im_get_context> pointer at some point.
-
-=cut
-*/
-
-static im_context_t
-get_context(void) {
- return im_get_context();
-}
/* just for use here */
#define im_extt imager_function_ext_table
-#define im_get_context() ((im_extt->f_im_get_context)())
-#define im_context_refinc(ctx, where) ((im_extt->f_im_context_refinc)((ctx), (where)))
-#define im_context_refdec(ctx, where) ((im_extt->f_im_context_refdec)((ctx), (where)))
-
#ifdef IMAGER_DEBUG_MALLOC
#define mymalloc(size) ((im_extt->f_mymalloc_file_line)((size), __FILE__, __LINE__))
#endif
-#define im_img_8_new(ctx, xsize, ysize, channels) ((im_extt->f_im_img_8_new)((ctx), (xsize), (ysize), (channels)))
-#define im_img_16_new(ctx, xsize, ysize, channels) ((im_extt->f_im_img_16_new)((ctx), (xsize), (ysize), (channels)))
-#define im_img_double_new(ctx, xsize, ysize, channels) ((im_extt->f_im_img_double_new)((ctx), (xsize), (ysize), (channels)))
-#define im_img_pal_new(ctx, xsize, ysize, channels, maxpal) ((im_extt->f_im_img_pal_new)((ctx), (xsize), (ysize), (channels), (maxpal)))
+#define i_img_8_new(xsize, ysize, channels) ((im_extt->f_i_img_8_new)((xsize), (ysize), (channels)))
+#define i_img_16_new(xsize, ysize, channels) ((im_extt->f_i_img_16_new)((xsize), (ysize), (channels)))
+#define i_img_double_new(xsize, ysize, channels) ((im_extt->f_i_img_double_new)((xsize), (ysize), (channels)))
+#define i_img_pal_new(xsize, ysize, channels, maxpal) ((im_extt->f_i_img_pal_new)((xsize), (ysize), (channels), (maxpal)))
#define i_img_destroy(im) ((im_extt->f_i_img_destroy)(im))
#define i_sametype(im, xsize, ysize) ((im_extt->f_i_sametype)((im), (xsize), (ysize)))
#define IMAGER_DIRECT_IMAGE_CALLS 1
#endif
-#if !IMAGER_DIRECT_IMAGE_CALLS
+#if IMAGER_DIRECT_IMAGE_CALLS
+#define i_ppix(im, x, y, val) (((im)->i_f_ppix)((im), (x), (y), (val)))
+#define i_gpix(im, x, y, val) (((im)->i_f_gpix)((im), (x), (y), (val)))
+#define i_ppixf(im, x, y, val) (((im)->i_f_ppixf)((im), (x), (y), (val)))
+#define i_gpixf(im, x, y, val) (((im)->i_f_gpixf)((im), (x), (y), (val)))
+#define i_plin(im, l, r, y, val) (((im)->i_f_plin)(im, l, r, y, val))
+#define i_glin(im, l, r, y, val) (((im)->i_f_glin)(im, l, r, y, val))
+#define i_plinf(im, l, r, y, val) (((im)->i_f_plinf)(im, l, r, y, val))
+#define i_glinf(im, l, r, y, val) (((im)->i_f_glinf)(im, l, r, y, val))
+#define i_gsamp(im, l, r, y, samps, chans, count) \
+ (((im)->i_f_gsamp)((im), (l), (r), (y), (samps), (chans), (count)))
+#define i_gsampf(im, l, r, y, samps, chans, count) \
+ (((im)->i_f_gsampf)((im), (l), (r), (y), (samps), (chans), (count)))
+
+#define i_findcolor(im, color, entry) \
+ (((im)->i_f_findcolor) ? ((im)->i_f_findcolor)((im), (color), (entry)) : 0)
+
+#define i_gpal(im, l, r, y, vals) \
+ (((im)->i_f_gpal) ? ((im)->i_f_gpal)((im), (l), (r), (y), (vals)) : 0)
+#define i_ppal(im, l, r, y, vals) \
+ (((im)->i_f_ppal) ? ((im)->i_f_ppal)((im), (l), (r), (y), (vals)) : 0)
+#define i_addcolors(im, colors, count) \
+ (((im)->i_f_addcolors) ? ((im)->i_f_addcolors)((im), (colors), (count)) : -1)
+#define i_getcolors(im, index, color, count) \
+ (((im)->i_f_getcolors) ? \
+ ((im)->i_f_getcolors)((im), (index), (color), (count)) : 0)
+#define i_setcolors(im, index, color, count) \
+ (((im)->i_f_setcolors) ? \
+ ((im)->i_f_setcolors)((im), (index), (color), (count)) : 0)
+#define i_colorcount(im) \
+ (((im)->i_f_colorcount) ? ((im)->i_f_colorcount)(im) : -1)
+#define i_maxcolors(im) \
+ (((im)->i_f_maxcolors) ? ((im)->i_f_maxcolors)(im) : -1)
+#define i_findcolor(im, color, entry) \
+ (((im)->i_f_findcolor) ? ((im)->i_f_findcolor)((im), (color), (entry)) : 0)
+#else
#define i_ppix(im, x, y, val) ((im_extt->f_i_ppix)((im), (x), (y), (val)))
#define i_gpix(im, x, y, val) ((im_extt->f_i_gpix)((im), (x), (y), (val)))
#define i_ppixf(im, x, y, val) ((im_extt->f_i_ppixf)((im), (x), (y), (val)))
#define i_quant_transparent(quant, indices, img, trans_index) \
((im_extt->f_i_quant_transparent)((quant), (indices), (img), (trans_index)))
-#define im_clear_error(ctx) ((im_extt->f_im_clear_error)(ctx))
-#define im_push_error(ctx, code, msg) ((im_extt->f_im_push_error)((ctx), (code), (msg)))
+#define i_clear_error() ((im_extt->f_i_clear_error)())
+#define i_push_error(code, msg) ((im_extt->f_i_push_error)((code), (msg)))
#define i_push_errorf (im_extt->f_i_push_errorf)
-#define im_push_errorvf(ctx, code, fmt, list) \
- ((im_extt->f_im_push_errorvf)((ctx), (code), (fmt), (list)))
+#define i_push_errorvf(code, fmt, list) \
+ ((im_extt->f_i_push_errorvf)((code), (fmt), (list)))
#define i_tags_new(tags) ((im_extt->f_i_tags_new)(tags))
#define i_tags_set(tags, name, data, size) \
#define i_rubthru(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy) \
((im_extt->f_i_rubthru)((im), (src), (tx), (ty), (src_minx), (src_miny), (src_maxx), (src_maxy)))
-#define im_set_image_file_limits(ctx, max_width, max_height, max_bytes) \
- ((im_extt->f_im_set_image_file_limits)((max_width), (max_height), (max_bytes)))
-#define im_get_image_file_limits(ctx, pmax_width, pmax_height, pmax_bytes) \
- ((im_extt->f_im_get_image_file_limits)((ctx), (pmax_width), (pmax_height), (pmax_bytes)))
-#define im_int_check_image_file_limits(ctx, width, height, channels, sample_size) \
- ((im_extt->f_im_int_check_image_file_limits)((ctx), (width), (height), (channels), (sample_size)))
+#define i_set_image_file_limits(max_width, max_height, max_bytes) \
+ ((im_extt->f_i_set_image_file_limits)((max_width), (max_height), (max_bytes)))
+#define i_get_image_file_limits(pmax_width, pmax_height, pmax_bytes) \
+ ((im_extt->f_i_get_image_file_limits)((pmax_width), (pmax_height), (pmax_bytes)))
+#define i_int_check_image_file_limits(width, height, channels, sample_size) \
+ ((im_extt->f_i_int_check_image_file_limits)((width), (height), (channels), (sample_size)))
#define i_img_setmask(img, mask) ((im_extt->f_i_img_setmask)((img), (mask)))
#define i_img_getmask(img) ((im_extt->f_i_img_getmask)(img))
#define i_img_get_height(img) ((im_extt->f_i_img_get_height)(img))
#define i_lhead(file, line) ((im_extt->f_i_lhead)((file), (line)))
#define i_loog (im_extt->f_i_loog)
-#define im_lhead(ctx, file, line) ((im_extt->f_im_lhead)((ctx), (file), (line)))
-#define im_loog (im_extt->f_im_loog)
-#define im_img_alloc(ctx) ((im_extt->f_im_img_alloc)(ctx))
-#define im_img_init(ctx, img) ((im_extt->fm_i_img_init)((ctx), (img)))
+#define i_img_alloc() ((im_extt->f_i_img_alloc)())
+#define i_img_init(img) ((im_extt->f_i_img_init)(img))
#define i_img_is_monochrome(img, zero_is_white) ((im_extt->f_i_img_is_monochrome)((img), (zero_is_white)))
#define i_io_close (im_extt->f_i_io_close)
#define i_io_set_buffered (im_extt->f_i_io_set_buffered)
#define i_io_gets (im_extt->f_i_io_gets)
-#define im_io_new_fd(ctx, fd) ((im_extt->f_im_io_new_fd)(ctx, fd))
-#define im_io_new_bufchain(ctx) ((im_extt->f_im_io_new_bufchain)(ctx))
-#define im_io_new_buffer(ctx, data, len, closecb, closedata) \
- ((im_extt->f_im_io_new_buffer)((ctx), (data), (len), (closecb), (closedata)))
-#define im_io_new_cb(ctx, p, readcb, writecb, seekcb, closecb, destroycb) \
- ((im_extt->f_im_io_new_cb)((ctx), (p), (readcb), (writecb), (seekcb), (closecb), (destroycb)))
+#define io_new_fd(fd) ((im_extt->f_io_new_fd)(fd))
+#define io_new_bufchain() ((im_extt->f_io_new_bufchain)())
+#define io_new_buffer(data, len, closecb, closedata) \
+ ((im_extt->f_io_new_buffer)((data), (len), (closecb), (closedata)))
+#define io_new_cb(p, readcb, writecb, seekcb, closecb, destroycb) \
+ ((im_extt->f_io_new_cb)((p), (readcb), (writecb), (seekcb), (closecb), (destroycb)))
#define io_slurp(ig, datap) ((im_extt->f_io_slurp)((ig), (datap)))
#define io_glue_destroy(ig) ((im_extt->f_io_glue_destroy)(ig))
-#define i_mutex_new() ((im_extt->f_i_mutex_new)())
-#define i_mutex_destroy(m) ((im_extt->f_i_mutex_destroy)(m))
-#define i_mutex_lock(m) ((im_extt->f_i_mutex_lock)(m))
-#define i_mutex_unlock(m) ((im_extt->f_i_mutex_unlock)(m))
-
-#define im_context_slot_new(destructor, where) ((im_extt->f_im_context_slot_new)((destructor), (where)))
-#define im_context_slot_get(ctx, slot) ((im_extt->f_im_context_slot_get)((ctx), (slot)))
-#define im_context_slot_set(ctx, slot, value) ((im_extt->f_im_context_slot_set)((ctx), (slot), (value)))
-
-#define im_push_errorf (im_extt->f_im_push_errorf)
-
#ifdef IMAGER_LOG
-#ifndef IMAGER_NO_CONTEXT
#define mm_log(x) { i_lhead(__FILE__,__LINE__); i_loog x; }
-#endif
-#define im_log(x) { im_lhead(aIMCTX, __FILE__,__LINE__); im_loog x; }
#else
#define mm_log(x)
#endif
+
#endif
Version 5 changed the return types of i_get_file_background() and
i_get_file_backgroundf() from void to int.
- Version 6 added
-
*/
-#define IMAGER_API_VERSION 6
+#define IMAGER_API_VERSION 5
/*
IMAGER_API_LEVEL is the level of the structure. New function pointers
void (*f_myfree_file_line)(void *p, char*file, int line);
void* (*f_myrealloc_file_line)(void *p, size_t newsize, char* file,int line);
- i_img *(*f_im_img_8_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels);
- i_img *(*f_im_img_16_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels);
- i_img *(*f_im_img_double_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels);
- i_img *(*f_im_img_pal_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels, int maxpal);
+ i_img *(*f_i_img_8_new)(i_img_dim xsize, i_img_dim ysize, int channels);
+ i_img *(*f_i_img_16_new)(i_img_dim xsize, i_img_dim ysize, int channels);
+ i_img *(*f_i_img_double_new)(i_img_dim xsize, i_img_dim ysize, int channels);
+ i_img *(*f_i_img_pal_new)(i_img_dim xsize, i_img_dim ysize, int channels, int maxpal);
void (*f_i_img_destroy)(i_img *im);
i_img *(*f_i_sametype)(i_img *im, i_img_dim xsize, i_img_dim ysize);
i_img *(*f_i_sametype_chans)(i_img *im, i_img_dim xsize, i_img_dim ysize, int channels);
void (*f_i_quant_transparent)(i_quantize *quant, i_palidx *indices,
i_img *img, i_palidx trans_index);
- void (*f_im_clear_error)(im_context_t ctx);
- void (*f_im_push_error)(im_context_t ctx, int code, char const *msg);
+ void (*f_i_clear_error)(void);
+ void (*f_i_push_error)(int code, char const *msg);
void (*f_i_push_errorf)(int code, char const *fmt, ...);
- void (*f_im_push_errorvf)(im_context_t ctx, int code, char const *fmt, va_list);
+ void (*f_i_push_errorvf)(int code, char const *fmt, va_list);
void (*f_i_tags_new)(i_img_tags *tags);
int (*f_i_tags_set)(i_img_tags *tags, char const *name, char const *data,
int (*f_i_rubthru)(i_img *im, i_img *src, i_img_dim tx, i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny, i_img_dim src_maxx, i_img_dim src_maxy);
/* IMAGER_API_LEVEL 2 functions */
- int (*f_im_set_image_file_limits)(im_context_t ctx, i_img_dim width, i_img_dim height, size_t bytes);
- int (*f_im_get_image_file_limits)(im_context_t ctx, i_img_dim *width, i_img_dim *height, size_t *bytes);
- int (*f_im_int_check_image_file_limits)(im_context_t ctx, i_img_dim width, i_img_dim height, int channels, size_t sample_size);
+ int (*f_i_set_image_file_limits)(i_img_dim width, i_img_dim height, size_t bytes);
+ int (*f_i_get_image_file_limits)(i_img_dim *width, i_img_dim *height, size_t *bytes);
+ int (*f_i_int_check_image_file_limits)(i_img_dim width, i_img_dim height, int channels, size_t sample_size);
int (*f_i_flood_fill_border)(i_img *im, i_img_dim seedx, i_img_dim seedy, const i_color *dcol, const i_color *border);
int (*f_i_flood_cfill_border)(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill, const i_color *border);
void (*f_i_loog)(int level, const char *msg, ...);
/* IMAGER_API_LEVEL 4 functions will be added here */
- i_img *(*f_im_img_alloc)(im_context_t ctx);
- void (*f_im_img_init)(im_context_t ctx, i_img *);
+ i_img *(*f_i_img_alloc)(void);
+ void (*f_i_img_init)(i_img *);
/* IMAGER_API_LEVEL 5 functions will be added here */
/* added i_psampf?_bits macros */
int (*f_i_io_set_buffered)(io_glue *ig, int buffered);
ssize_t (*f_i_io_gets)(io_glue *ig, char *, size_t, int);
- i_io_glue_t *(*f_im_io_new_fd)(im_context_t ctx, int fd);
- i_io_glue_t *(*f_im_io_new_bufchain)(im_context_t ctx);
- i_io_glue_t *(*f_im_io_new_buffer)(im_context_t ctx, const char *data, size_t len, i_io_closebufp_t closecb, void *closedata);
- i_io_glue_t *(*f_im_io_new_cb)(im_context_t ctx, void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb);
+ i_io_glue_t *(*f_io_new_fd)(int fd);
+ i_io_glue_t *(*f_io_new_bufchain)(void);
+ i_io_glue_t *(*f_io_new_buffer)(const char *data, size_t len, i_io_closebufp_t closecb, void *closedata);
+ i_io_glue_t *(*f_io_new_cb)(void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb);
size_t (*f_io_slurp)(i_io_glue_t *ig, unsigned char **c);
void (*f_io_glue_destroy)(i_io_glue_t *ig);
/* IMAGER_API_LEVEL 8 functions will be added here */
- im_context_t (*f_im_get_context)(void);
-
- void (*f_im_push_errorf)(im_context_t , int code, char const *fmt, ...);
- void (*f_im_lhead)( im_context_t, const char *file, int line );
- void (*f_im_loog)(im_context_t, int level,const char *msg, ... ) I_FORMAT_ATTR(3,4);
- void (*f_im_context_refinc)(im_context_t, const char *where);
- void (*f_im_context_refdec)(im_context_t, const char *where);
- i_errmsg *(*f_im_errors)(im_context_t);
- i_mutex_t (*f_i_mutex_new)(void);
- void (*f_i_mutex_destroy)(i_mutex_t m);
- void (*f_i_mutex_lock)(i_mutex_t m);
- void (*f_i_mutex_unlock)(i_mutex_t m);
- im_slot_t (*f_im_context_slot_new)(im_slot_destroy_t, const char *);
- int (*f_im_context_slot_set)(im_context_t, im_slot_t, void *);
- void *(*f_im_context_slot_get)(im_context_t, im_slot_t);
+
} im_ext_funcs;
#define PERL_FUNCTION_TABLE_NAME "Imager::__ext_func_table"
=cut
*/
-#define IMAGER_NO_CONTEXT
-
#include "imager.h"
#include "imageri.h"
((((i_sample16_t *)(bytes))[offset]+127) / 257)
/*
-=item im_img_16_new(ctx, x, y, ch)
-X<im_img_16_new API>X<i_img_16_new API>
+=item i_img_16_new(x, y, ch)
+
=category Image creation/destruction
-=synopsis i_img *img = im_img_16_new(aIMCTX, width, height, channels);
=synopsis i_img *img = i_img_16_new(width, height, channels);
Create a new 16-bit/sample image.
Returns the image on success, or NULL on failure.
-Also callable as C<i_img_16_new(x, y, ch)>
-
=cut
*/
-i_img *
-im_img_16_new(pIMCTX, i_img_dim x, i_img_dim y, int ch) {
+i_img *i_img_16_new(i_img_dim x, i_img_dim y, int ch) {
i_img *im;
size_t bytes, line_bytes;
- im_log((aIMCTX, 1,"i_img_16_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
+ mm_log((1,"i_img_16_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
i_DFc(x), i_DFc(y), ch));
if (x < 1 || y < 1) {
- im_push_error(aIMCTX, 0, "Image sizes must be positive");
+ i_push_error(0, "Image sizes must be positive");
return NULL;
}
if (ch < 1 || ch > MAXCHANNELS) {
- im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS);
+ i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
return NULL;
}
bytes = x * y * ch * 2;
if (bytes / y / ch / 2 != x) {
- im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation");
+ i_push_errorf(0, "integer overflow calculating image allocation");
return NULL;
}
working with the image */
line_bytes = sizeof(i_fcolor) * x;
if (line_bytes / x != sizeof(i_fcolor)) {
- im_push_error(aIMCTX, 0, "integer overflow calculating scanline allocation");
+ i_push_error(0, "integer overflow calculating scanline allocation");
return NULL;
}
- im = im_img_alloc(aIMCTX);
+ im = i_img_alloc();
*im = IIM_base_16bit_direct;
i_tags_new(&im->tags);
im->xsize = x;
im->idata = mymalloc(im->bytes);
memset(im->idata, 0, im->bytes);
- im_img_init(aIMCTX, im);
+ i_img_init(im);
return im;
}
i_img *targ;
i_fcolor *line;
i_img_dim y;
- dIMCTXim(im);
- targ = im_img_16_new(aIMCTX, im->xsize, im->ysize, im->channels);
+ targ = i_img_16_new(im->xsize, im->ysize, im->channels);
if (!targ)
return NULL;
line = mymalloc(sizeof(i_fcolor) * im->xsize);
/* make sure we have good channel numbers */
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return 0;
}
}
}
else {
if (chan_count <= 0 || chan_count > im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
+ i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
chan_count);
return 0;
}
/* make sure we have good channel numbers */
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return 0;
}
}
}
else {
if (chan_count <= 0 || chan_count > im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
+ i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
chan_count);
return 0;
}
/* make sure we have good channel numbers */
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return -1;
}
}
}
else {
if (chan_count <= 0 || chan_count > im->channels) {
- dIMCTXim(im);
i_push_error(0, "Invalid channel count");
return -1;
}
return count;
}
else {
- dIMCTXim(im);
i_push_error(0, "Image position outside of image");
return -1;
}
i_img_dim off;
if (bits != 16) {
- dIMCTXim(im);
i_push_error(0, "Invalid bits for 16-bit image");
return -1;
}
/* make sure we have good channel numbers */
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return -1;
}
}
}
else {
if (chan_count <= 0 || chan_count > im->channels) {
- dIMCTXim(im);
i_push_error(0, "Invalid channel count");
return -1;
}
return count;
}
else {
- dIMCTXim(im);
i_push_error(0, "Image position outside of image");
return -1;
}
int all_in_mask = 1;
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return -1;
}
if (!((1 << chans[ch]) & im->ch_mask))
}
else {
if (chan_count <= 0 || chan_count > im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
+ i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
chan_count);
return -1;
}
return count;
}
else {
- dIMCTXim(im);
i_push_error(0, "Image position outside of image");
return -1;
}
int all_in_mask = 1;
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return -1;
}
if (!((1 << chans[ch]) & im->ch_mask))
}
else {
if (chan_count <= 0 || chan_count > im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
+ i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
chan_count);
return -1;
}
return count;
}
else {
- dIMCTXim(im);
i_push_error(0, "Image position outside of image");
return -1;
}
-#define IMAGER_NO_CONTEXT
-
#include "imager.h"
#include "imageri.h"
}*/
/*
-=item im_img_8_new(ctx, x, y, ch)
-X<im_img_8_new API>X<i_img_8_new API>
+=item i_img_8_new(x, y, ch)
+
=category Image creation/destruction
-=synopsis i_img *img = im_img_8_new(aIMCTX, width, height, channels);
+
=synopsis i_img *img = i_img_8_new(width, height, channels);
Creates a new image object I<x> pixels wide, and I<y> pixels high with
=cut
*/
+
i_img *
-im_img_8_new(pIMCTX, i_img_dim x,i_img_dim y,int ch) {
+i_img_8_new(i_img_dim x,i_img_dim y,int ch) {
i_img *im;
- im_log((aIMCTX, 1,"im_img_8_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
+ mm_log((1,"IIM_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
i_DFc(x), i_DFc(y), ch));
- im = im_img_empty_ch(aIMCTX, NULL,x,y,ch);
+ im=i_img_empty_ch(NULL,x,y,ch);
+
+ mm_log((1,"(%p) <- IIM_new\n",im));
+ return im;
+}
+
+/*
+=item i_img_new()
+
+Create new image reference - notice that this isn't an object yet and
+this should be fixed asap.
+
+=cut
+*/
+
+
+i_img *
+i_img_new() {
+ i_img *im;
+
+ mm_log((1,"i_img_struct()\n"));
+
+ im = i_img_alloc();
+
+ *im = IIM_base_8bit_direct;
+ im->xsize=0;
+ im->ysize=0;
+ im->channels=3;
+ im->ch_mask=MAXINT;
+ im->bytes=0;
+ im->idata=NULL;
+
+ i_img_init(im);
- im_log((aIMCTX, 1,"(%p) <- IIM_new\n",im));
+ mm_log((1,"(%p) <- i_img_struct\n",im));
return im;
}
*/
i_img *
-im_img_empty(pIMCTX, i_img *im,i_img_dim x,i_img_dim y) {
- im_log((aIMCTX, 1,"i_img_empty(*im %p, x %" i_DF ", y %" i_DF ")\n",
+i_img_empty(i_img *im,i_img_dim x,i_img_dim y) {
+ mm_log((1,"i_img_empty(*im %p, x %" i_DF ", y %" i_DF ")\n",
im, i_DFc(x), i_DFc(y)));
- return im_img_empty_ch(aIMCTX, im, x, y, 3);
+ return i_img_empty_ch(im, x, y, 3);
}
/*
*/
i_img *
-im_img_empty_ch(pIMCTX, i_img *im,i_img_dim x,i_img_dim y,int ch) {
+i_img_empty_ch(i_img *im,i_img_dim x,i_img_dim y,int ch) {
size_t bytes;
- im_log((aIMCTX, 1,"i_img_empty_ch(*im %p, x %" i_DF ", y %" i_DF ", ch %d)\n",
+ mm_log((1,"i_img_empty_ch(*im %p, x %" i_DF ", y %" i_DF ", ch %d)\n",
im, i_DFc(x), i_DFc(y), ch));
if (x < 1 || y < 1) {
- im_push_error(aIMCTX, 0, "Image sizes must be positive");
+ i_push_error(0, "Image sizes must be positive");
return NULL;
}
if (ch < 1 || ch > MAXCHANNELS) {
- im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS);
+ i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
return NULL;
}
/* check this multiplication doesn't overflow */
bytes = x*y*ch;
if (bytes / y / ch != x) {
- im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation");
+ i_push_errorf(0, "integer overflow calculating image allocation");
return NULL;
}
if (im == NULL)
- im = im_img_alloc(aIMCTX);
+ im = i_img_alloc();
memcpy(im, &IIM_base_8bit_direct, sizeof(i_img));
i_tags_new(&im->tags);
im->ch_mask = MAXINT;
im->bytes=bytes;
if ( (im->idata=mymalloc(im->bytes)) == NULL)
- im_fatal(aIMCTX, 2,"malloc() error\n");
+ i_fatal(2,"malloc() error\n");
memset(im->idata,0,(size_t)im->bytes);
im->ext_data = NULL;
- im_img_init(aIMCTX, im);
+ i_img_init(im);
- im_log((aIMCTX, 1,"(%p) <- i_img_empty_ch\n",im));
+ mm_log((1,"(%p) <- i_img_empty_ch\n",im));
return im;
}
/* make sure we have good channel numbers */
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return 0;
}
}
}
else {
if (chan_count <= 0 || chan_count > im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
+ i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
chan_count);
return 0;
}
unsigned char *data;
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
}
}
if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
/* make sure we have good channel numbers */
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return 0;
}
}
}
else {
if (chan_count <= 0 || chan_count > im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
+ i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
chan_count);
return 0;
}
int all_in_mask = 1;
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return -1;
}
if (!((1 << chans[ch]) & im->ch_mask))
}
else {
if (chan_count <= 0 || chan_count > im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
+ i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
chan_count);
return -1;
}
return count;
}
else {
- dIMCTXim(im);
i_push_error(0, "Image position outside of image");
return -1;
}
int all_in_mask = 1;
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return -1;
}
if (!((1 << chans[ch]) & im->ch_mask))
}
else {
if (chan_count <= 0 || chan_count > im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
+ i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
chan_count);
return -1;
}
return count;
}
else {
- dIMCTXim(im);
i_push_error(0, "Image position outside of image");
return -1;
}
=cut
*/
-#define IMAGER_NO_CONTEXT
#include "imager.h"
#include "imageri.h"
};
/*
-=item im_img_double_new(ctx, x, y, ch)
-X<im_img_double_new API>X<i_img_double_new API>
+=item i_img_double_new(i_img_dim x, i_img_dim y, int ch)
=category Image creation/destruction
-=synopsis i_img *img = im_img_double_new(aIMCTX, width, height, channels);
=synopsis i_img *img = i_img_double_new(width, height, channels);
Creates a new double per sample image.
-Also callable as C<i_img_double_new(width, height, channels)>.
-
=cut
*/
-i_img *
-im_img_double_new(pIMCTX, i_img_dim x, i_img_dim y, int ch) {
+i_img *i_img_double_new(i_img_dim x, i_img_dim y, int ch) {
size_t bytes;
i_img *im;
- im_log((aIMCTX, 1,"i_img_double_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
+ mm_log((1,"i_img_double_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
i_DFc(x), i_DFc(y), ch));
if (x < 1 || y < 1) {
- im_push_error(aIMCTX, 0, "Image sizes must be positive");
+ i_push_error(0, "Image sizes must be positive");
return NULL;
}
if (ch < 1 || ch > MAXCHANNELS) {
- im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS);
+ i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
return NULL;
}
bytes = x * y * ch * sizeof(double);
if (bytes / y / ch / sizeof(double) != x) {
- im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation");
+ i_push_errorf(0, "integer overflow calculating image allocation");
return NULL;
}
- im = im_img_alloc(aIMCTX);
+ im = i_img_alloc();
*im = IIM_base_double_direct;
i_tags_new(&im->tags);
im->xsize = x;
im->ext_data = NULL;
im->idata = mymalloc(im->bytes);
memset(im->idata, 0, im->bytes);
- im_img_init(aIMCTX, im);
+ i_img_init(im);
return im;
}
/* make sure we have good channel numbers */
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- dIMCTXim(im);
- im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
+ i_push_errorf(0, "No channel %d in this image", chans[ch]);
return 0;
}
}