Σχεδίαση raster με το Imager#

Το Imager είναι το βαρύ όχημα του raster: δημιουργήστε μια εικόνα, σχεδιάστε πάνω της, φιλτράρετέ την, αποθηκεύστε την. Συντηρείται ενεργά, συνδέει τα δικά του αντίγραφα των βιβλιοθηκών μορφών ώστε PNG, JPEG, TIFF, GIF και WEBP να λειτουργούν όλα εκ των έξω, και τα πρωτογενή σχεδίασής του είναι αυτά από το κεφάλαιο των αλγορίθμων που τρέχουν με ταχύτητα C. Αν ξεκινάτε ένα έργο raster σε Perl σήμερα και δεν έχετε λόγο να προτιμήσετε κάτι άλλο, ξεκινήστε εδώ.

Κάθε μέθοδος σχεδίασης επιστρέφει ψευδές σε αποτυχία και ορίζει το errstr, οπότε το ιδίωμα είναι να ελέγχετε και να αναφέρετε:

use Imager;

my $img = Imager->new(xsize => 400, ysize => 300, channels => 4)
    or die Imager->errstr;

Το channels => 4 ζητά RGBA (red, green, blue, alpha)· χρησιμοποιήστε 3 για αδιαφανές RGB. Το κανάλι άλφα είναι αυτό που επιτρέπει στη σύνθεση από το κεφάλαιο των θεμελίων να λειτουργεί όταν σχεδιάζετε μια εικόνα πάνω σε μια άλλη.

Χρώματα#

Οπουδήποτε μια μέθοδος παίρνει color =>, μπορείτε να περάσετε ένα όνομα, μια δεκαεξαδική συμβολοσειρά, ένα αντικείμενο Imager::Color, ή μια απλή αναφορά πίνακα:

my $red   = Imager::Color->new('red');
my $red2  = Imager::Color->new('#FF0000');
my $red3  = Imager::Color->new(255, 0, 0);
my $trans = Imager::Color->new(255, 0, 0, 128);   # 50% alpha

$img->box(color => [0, 128, 255], filled => 1);   # array-ref, no object

Η μορφή της αναφοράς πίνακα είναι η λιγότερο τυπική για ένα εφάπαξ χρώμα και είναι αυτή που χρησιμοποιούν τα περισσότερα από τα παρακάτω παραδείγματα.

Τα πρωτογενή#

Σημειώστε προσεκτικά τα ονόματα των παραμέτρων, γιατί δεν έχουν όλα το ίδιο σχήμα. Τα κουτιά χρησιμοποιούν συντεταγμένες γωνιών xmin/ymin/xmax/ymax· οι κύκλοι και τα τόξα χρησιμοποιούν ένα κέντρο x/y με μια ακτίνα r· τα τόξα προσθέτουν μοίρες αρχής και τέλους d1/d2.

# fill the whole canvas white first
$img->box(color => 'white', filled => 1);

# a line; aa => 1 requests anti-aliasing
$img->line(x1 => 0, y1 => 0, x2 => 399, y2 => 299,
           color => [255, 0, 0], aa => 1);

# an outlined box (no fill) and a filled one
$img->box(xmin => 20, ymin => 20, xmax => 120, ymax => 90,
          color => 'black');
$img->box(xmin => 140, ymin => 20, xmax => 240, ymax => 90,
          color => [200, 220, 255], filled => 1);

# a filled circle: center (200,150), radius 60
$img->circle(x => 200, y => 150, r => 60, color => [0, 128, 255]);

# an arc is a pie slice from d1 to d2 degrees
$img->arc(x => 200, y => 150, r => 80, d1 => 0, d2 => 120,
          color => 'yellow');

# a polygon from a list of [x, y] points
$img->polygon(points => [[300, 40], [380, 40], [340, 110]],
              color => [120, 200, 120]);

# a polyline is an open path; it takes no fill
$img->polyline(points => [[300, 130], [340, 200], [380, 130]],
               color => 'black', aa => 1);

# flood fill from a seed point out to a border
$img->flood_fill(x => 5, y => 5, color => [245, 245, 245]);

Δύο παγίδες που αξίζει να αναφερθούν μία φορά. Το box γεμίζει μόνο όταν περνάτε filled => 1 (ή ένα μοτίβο fill =>)· χωρίς αυτό παίρνετε ένα περίγραμμα. Το polyline σχεδιάζει μια ανοιχτή διαδρομή και δεν δέχεται fill, σε αντίθεση με το polygon που κλείνει και μπορεί να γεμίσει. Όταν ένα σχήμα βγαίνει ως περίγραμμα ενώ το περιμένατε γεμάτο, ή ένα γέμισμα σιωπηλά δεν κάνει τίποτα, μία από αυτές τις δύο είναι ο λόγος.

Φόρτωση, κλιμάκωση και αποθήκευση#

Η ανάγνωση και η εγγραφή συμπεραίνουν τη μορφή από την επέκταση του ονόματος αρχείου, ή μπορείτε να την επιβάλετε με type =>:

my $photo = Imager->new;
$photo->read(file => 'input.jpg') or die $photo->errstr;

# scale by a factor, or to fit a box
my $thumb = $photo->scale(scalefactor => 0.25);
my $fit   = $photo->scale(xpixels => 200, ypixels => 200, type => 'min');

$thumb->write(file => 'thumb.png') or die $thumb->errstr;

Το scale επιστρέφει μια νέα εικόνα· δεν τροποποιεί την αρχική. Η μορφή type => 'min' κλιμακώνει ώστε η εικόνα να χωρά μέσα στο δοσμένο κουτί διατηρώντας τον λόγο διαστάσεων· το 'max' γεμίζει το κουτί (περικόπτοντας την υπερχείλιση όταν έπειτα περικόψετε)· το 'nonprop' αγνοεί τον λόγο διαστάσεων και τεντώνει ακριβώς στα pixel που ονομάσατε.

Φίλτρα#

Το filter εφαρμόζει ένα εφέ επιτόπου, ονομασμένο μέσω type =>. Η συνέλιξη από το κεφάλαιο των αλγορίθμων είναι εδώ ως ενσωματωμένο θόλωμα Gauss και unsharp masking, συν ένα γενικό conv για τον δικό σας πυρήνα:

# Gaussian blur; larger stddev is more blur
$img->filter(type => 'gaussian', stddev => 2.5);

# unsharp mask to sharpen; both params optional
$img->filter(type => 'unsharpmask', stddev => 2.0, scale => 1.0);

# your own 1-D convolution coefficients (a horizontal blur here)
$img->filter(type => 'conv', coef => [0.25, 0.5, 0.25]);

# contrast, mosaic (pixelate), and inversion are all filters too
$img->filter(type => 'contrast', intensity => 1.4);
$img->filter(type => 'mosaic', size => 8);
$img->filter(type => 'hardinvert');

Το πλήρες σύνολο περιλαμβάνει τα gaussian, gaussian2 (ξεχωριστές αποκλίσεις x και y), conv, unsharpmask, contrast, mosaic, noise, hardinvert, autolevels, postlevels, και τους διαδικαστικούς γεννήτορες υφής fountain, gradgen, radnoise και turbnoise. Καταφύγετε στο ονομασμένο φίλτρο πριν γράψετε τον δικό σας βρόχο pixel· κατεβείτε σε μια λίστα συντελεστών conv ή σε χειροκίνητη πρόσβαση μόνο όταν τίποτα ενσωματωμένο δεν ταιριάζει.

Ένα πλήρες πρόγραμμα#

Συνθέτοντάς τα: μια μικρή αφίσα με ένα φόντο, μερικά σχήματα, ένα πέρασμα θολώματος και μια αποθηκευμένη μικρογραφία.

use strict;
use warnings;
use Imager;

my $img = Imager->new(xsize => 400, ysize => 300, channels => 4)
    or die Imager->errstr;

$img->box(color => [30, 30, 60], filled => 1);              # dark bg
$img->circle(x => 120, y => 150, r => 70, color => [255, 200, 60]);
$img->circle(x => 260, y => 150, r => 70, color => [60, 200, 255]);
$img->filter(type => 'gaussian', stddev => 1.2);           # soften
$img->line(x1 => 0, y1 => 250, x2 => 399, y2 => 250,
           color => 'white', aa => 1);

$img->write(file => 'poster.png') or die $img->errstr;
$img->scale(scalefactor => 0.5)->write(file => 'poster-thumb.png')
    or die $img->errstr;

Πότε το Imager είναι το λάθος εργαλείο#

Το Imager είναι raster, οπότε έχει τον περιορισμό του raster: έχει σταθερή ανάλυση, και η κλιμάκωση πέρα από αυτήν υποβαθμίζει. Για έξοδο ανεξάρτητη από την ανάλυση (ένα λογότυπο που πρέπει να εκτυπώνεται ευκρινώς σε οποιοδήποτε μέγεθος, ένα διάγραμμα προορισμένο για τον ιστό ως markup) θέλετε ένα εργαλείο vector, που καλύπτεται στο Cairo και SVG. Για μια υπάρχουσα βάση κώδικα χτισμένη πάνω σε GD ή ImageMagick, ή για τα ειδικά τους δυνατά σημεία, δείτε το επόμενο κεφάλαιο. Και όταν η σχεδίαση πρέπει να εμφανιστεί σε ένα ζωντανό παράθυρο αντί για ένα αρχείο, αυτό είναι το κεφάλαιο των εργαλειοθηκών GUI. Για οτιδήποτε είναι «φτιάξε ή τροποποίησε ένα bitmap στον δίσκο», το Imager είναι η απάντηση.