File Coverage

blib/lib/OCBNET/Image/GD.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             ###################################################################################################
2             # Copyright 2013/2014 by Marcel Greter
3             # This file is part of OCBNET-WebSprite (GPL3)
4             ####################################################################################################
5             package OCBNET::Image::GD;
6             ####################################################################################################
7             our $VERSION = '1.0.2';
8             ####################################################################################################
9              
10 4     4   21 use Carp;
  4         5  
  4         222  
11 4     4   19 use strict;
  4         14  
  4         120  
12 4     4   19 use warnings;
  4         13  
  4         5143  
13              
14             ####################################################################################################
15              
16 4     4   2814 use GD;
  0            
  0            
17              
18             ####################################################################################################
19              
20             sub new
21             {
22             # create a dummy object
23             # init first image later
24             return bless {}, $_[0];
25             }
26              
27             ####################################################################################################
28             # read image from filepath
29             ####################################################################################################
30              
31             sub Read
32             {
33              
34             # get input arguments
35             my ($pkg, $path) = @_;
36              
37             # initialize a new image from the file path
38             my $self->{'image'} = GD::Image->new($path);
39             # implement proper error handling here
40              
41             # true color image with alpha channel
42             $self->{'image'}->alphaBlending(1);
43             $self->{'image'}->trueColor(1);
44              
45             # mimic imagemagick
46             return '';
47              
48             }
49             # EO Read
50              
51             ####################################################################################################
52             # read image from data
53             ####################################################################################################
54              
55             sub BlobToImage
56             {
57              
58             # get input arguments
59             my ($self, $blob) = @_;
60              
61             # initialize a new image from given blob
62             $self->{'image'} = GD::Image->new($blob);
63              
64             # implement proper error handling here
65              
66             # true color image with alpha channel
67             $self->{'image'}->alphaBlending(1);
68             $self->{'image'}->trueColor(1);
69              
70             # mimic imagemagick
71             return undef;
72              
73             }
74             # EO BlobToImage
75              
76             ####################################################################################################
77             # write image to data
78             ####################################################################################################
79              
80             sub ImageToBlob
81             {
82              
83             # get input arguments
84             my ($self) = @_;
85              
86             # make sure alpha channel is saved
87             $self->{'image'}->saveAlpha(1);
88              
89             # return png data for image
90             return $self->{'image'}->png;
91              
92             }
93             # EO ImageToBlob
94              
95             ####################################################################################################
96             # Image-Magick Get interface
97             # Only implement base features
98             ####################################################################################################
99              
100             sub Get
101             {
102              
103             # get input arguments
104             my ($self, $key) = @_;
105              
106             # so far only dimension getting is implemented
107             if ($key eq 'height') { $self->{'image'}->height }
108             elsif ($key eq 'width') { $self->{'image'}->width }
109             else { Carp::croak "Get $key not implemented"; }
110              
111             }
112             # EO Get
113              
114             ####################################################################################################
115             # Image-Magick Set interface
116             # Only implement base features
117             # Allocate new image on set size
118             ####################################################################################################
119              
120             sub Set
121             {
122              
123             # get input arguments
124             my ($self, $key, $value) = @_;
125              
126             # main feature
127             if ($key eq 'size')
128             {
129             # get dimensions from magick string
130             my ($width, $height) = split /x/, $value, 2;
131             # create new truecolor image with dimensions
132             my $image = GD::Image->new($width, $height, 1);
133             # make sure the background is fully transparent
134             my $bkg = $image->colorAllocateAlpha(0, 0, 0, 127);
135             $image->alphaBlending(0); # replace pixels fully
136             $image->filledRectangle(0, 0, $width, $height, $bkg);
137             $image->alphaBlending(1); # bleed pixel over now
138             # assign main image object
139             $self->{'image'} = $image;
140             }
141              
142             # just ignore some parameters
143             # not even sure what they do
144             elsif ($key eq 'matte') { }
145             elsif ($key eq 'magick') { }
146              
147             # everything else is considered a fatal error
148             else { Carp::croak "Set $key not implemented" }
149              
150             }
151             # EO Set
152              
153             ####################################################################################################
154             # just ignore some methods
155             ####################################################################################################
156              
157             sub Quantize { }
158              
159             ####################################################################################################
160             # used to draw background color
161             ####################################################################################################
162              
163             sub ReadImage
164             {
165              
166             # get input arguments
167             my ($self, $value) = @_;
168              
169             # get the main image object
170             my $image = $self->{'image'};
171             # assertion that we have an image object
172             die "Crop without image" unless $image;
173             # fetch the image dimensions
174             my $width = $image->width;
175             my $height = $image->height;
176              
177             # background
178             my $color;
179              
180             # match against specific image-magick syntax for rgba color
181             if ($value =~ m/^xc:rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+|0?\.\d+)\s*\)$/)
182             { $color = $image->colorAllocateAlpha(int($1), int($2), int($3), int(127*0.75)) }
183             elsif ($value =~ m/^xc:transparent$/) { $color = $image->colorAllocateAlpha(0, 0, 0, 127) }
184             else { Carp::croak "Invalid ReadImage color definition <$value>"; }
185              
186             # draw the background rectangle
187             $image->alphaBlending(0); # bleed pixel fully
188             $image->filledRectangle(0, 0, $width, $height, $color);
189             $image->alphaBlending(1); # bleed pixel over now
190              
191             # mimic imagemagick
192             return $self;
193              
194             }
195             # EO ReadImage
196              
197             ####################################################################################################
198             # draw image over another
199             ####################################################################################################
200              
201             sub Composite
202             {
203              
204             # get input arguments
205             my ($self, %options) = @_;
206              
207             # get composite action argument
208             my $action = $options{'compose'};
209              
210             # only support over action
211             if ($action eq 'over')
212             {
213             # get coordinates from options
214             my $x = $options{'x'} || 0;
215             my $y = $options{'y'} || 0;
216             # get image to draw from options
217             my $image = $options{'image'};
218             # assertion that we have an image
219             die "Compose without image" unless $image;
220             # get OCBNET::Image object
221             $image = $image->{'image'};
222             # get dimensions to draw
223             my $width = $image->width;
224             my $height = $image->height;
225             # copy the image in option into our own canvas at position
226             $self->{'image'}->copy($image, $x, $y, 0, 0, $width, $height)
227             }
228             else
229             {
230             # give an error message (bad implementor)
231             Carp::croak "Composite $action not implemented";
232             }
233              
234             # mimic imagemagick
235             return $self;
236              
237             }
238             # EO Composite
239              
240             ####################################################################################################
241             # crop existing image
242             ####################################################################################################
243              
244             sub Crop
245             {
246              
247             # get input arguments
248             my ($self, %options) = @_;
249              
250             # just return if nothing is to be done
251             return $self unless scalar %options;
252              
253             # get the main image object
254             my $image = $self->{'image'};
255              
256             # assertion that we have an image object
257             die "Crop without image" unless $image;
258              
259             # get coordinates from options
260             my $x = $options{'x'} || 0;
261             my $y = $options{'y'} || 0;
262             # fetch the image dimensions or defaults to rest
263             my $width = $options{'width'} || $image->width - $x;
264             my $height = $options{'height'} || $image->height - $y;
265              
266             # create a new image for cropped section
267             my $crop = GD::Image->new($width, $height, 1);
268              
269             # init new image with transparent background
270             my $bkg = $crop->colorAllocateAlpha(0, 0, 0, 127);
271             $crop->alphaBlending(0); # replace pixels fully
272             $crop->filledRectangle(0, 0, $width, $height, $bkg);
273             # copy cropped section from source to destination
274             $crop->copy($image, 0, 0, $x, $y, $width, $height);
275             $crop->alphaBlending(1); # bleed pixel over now
276              
277             # re-assign cropped image
278             $self->{'image'} = $crop;
279              
280             # return ourself
281             return $self;
282              
283             }
284             # EO Crop
285              
286             ####################################################################################################
287             # crop existing image
288             ####################################################################################################
289              
290             sub clone
291             {
292              
293             # get input arguments
294             my ($self) = @_;
295              
296             # get the main image object
297             my $image = $self->{'image'};
298             # assertion that we have an image object
299             die "Crop without image" unless $image;
300             # fetch the image dimensions
301             my $width = $image->width;
302             my $height = $image->height;
303              
304             # create a new image for a complete copy
305             my $copy = GD::Image->new($width, $height, 1);
306              
307             # init new image with transparent background
308             my $bkg = $copy->colorAllocateAlpha(0, 0, 0, 127);
309             $copy->alphaBlending(0); # replace pixels fully
310             $copy->filledRectangle(0, 0, $width, $height, $bkg);
311             # copy complete canvas from source to destination
312             $copy->copy($image, 0, 0, 0, 0, $width, $height);
313             $copy->alphaBlending(1); # bleed pixel over now
314              
315             # create new object with clone
316             my $clone = { 'image' => $copy };
317              
318             # bless new object into package
319             return bless $clone, ref $self;
320              
321             }
322             # EO clone
323              
324             ####################################################################################################
325             ####################################################################################################
326             1;