Διανυσματικά γραφικά: Cairo και SVG#
Τα εργαλεία raster δεσμεύονται σε μια ανάλυση· τα εργαλεία vector περιγράφουν σχήματα και αποφασίζουν τα pixel αργότερα, ή ποτέ. Αυτό το κεφάλαιο καλύπτει τις δύο διαδρομές vector στην Perl. Το Cairo είναι μια πλήρης εξομαλυμένη μηχανή 2D που rasterize διαδρομές σε μια επιφάνεια pixel (ή σε PDF και SVG): σχεδιάζετε με συντεταγμένες πραγματικών αριθμών και υπολογίζει την κάλυψη. Το SVG παράγει markup SVG, μια κειμενική περιγραφή σχημάτων που ένας φυλλομετρητής ή αποδότης σχεδιάζει αργότερα σε όποιο μέγεθος του αρέσει. Χρησιμοποιήστε το Cairo όταν χρειάζεστε pixel τώρα με την ποιότητα ενός σωστού rasterizer· χρησιμοποιήστε το SVG όταν θέλετε έξοδο ανεξάρτητη από την ανάλυση ως αρχείο που καταναλώνουν άλλα εργαλεία.
Το Cairo επιστρέφει επίσης στο κεφάλαιο 9: η pperl αποστέλλει μια εγγενή επανυλοποίησή του, οπότε ο ίδιος κώδικας τρέχει χωρίς εγκατεστημένο το Cairo του CPAN, και εκείνο το κεφάλαιο δείχνει πώς λειτουργεί η εγγενής σύνδεση. Εδώ είναι το συνηθισμένο άρθρωμα του CPAN.
Cairo: διαδρομές και το μοντέλο σχεδίασης#
Το μοντέλο του Cairo είναι μια διαδρομή χτισμένη από τμήματα, που έπειτα είτε χαράσσεται (σχεδιάζεται το περίγραμμα) είτε γεμίζει (βάφεται το εσωτερικό). Ορίζετε ένα χρώμα πηγής, χτίζετε μια διαδρομή με move_to και line_to και καμπύλες, και την επικυρώνετε. Τα χρώματα είναι floats στο 0 .. 1, όχι 0 .. 255.
use Cairo;
# an ARGB surface is a pixel buffer with alpha
my $surface = Cairo::ImageSurface->create('argb32', 200, 200);
my $cr = Cairo::Context->create($surface);
# paint a white background: set source, then paint fills everything
$cr->set_source_rgb(1, 1, 1);
$cr->paint;
# a stroked path
$cr->set_source_rgb(0, 0, 0);
$cr->set_line_width(3);
$cr->move_to(20, 20);
$cr->line_to(180, 20);
$cr->curve_to(180, 100, 20, 100, 20, 180); # a bezier curve
$cr->stroke;
# a filled, semi-transparent circle (arc angles are in radians)
$cr->arc(100, 100, 40, 0, 6.28318); # full circle = 2*pi
$cr->set_source_rgba(1, 0, 0, 0.5); # red at 50% alpha
$cr->fill;
$surface->write_to_png('output.png');
Τρία πράγματα να αφομοιώσετε. Οι συντεταγμένες είναι πραγματικοί αριθμοί, οπότε το move_to(100.5, 47.25) έχει νόημα και η μετατόπιση μισού pixel από το κεφάλαιο των θεμελίων είναι ο τρόπος με τον οποίο παίρνετε ευκρινείς λεπτές γραμμές. Οι γωνίες τόξου είναι σε ακτίνια, όχι σε μοίρες, οπότε ένας πλήρης κύκλος είναι 2 * pi. Και το άλφα του set_source_rgba σας δίνει τη σύνθεση δωρεάν: γεμίστε ή χαράξτε με άλφα μικρότερο του 1 και το Cairo αναμειγνύει πάνω σε ό,τι υπάρχει ήδη εκεί.
Τα stroke και fill καταναλώνουν την τρέχουσα διαδρομή. Αν θέλετε να γεμίσετε και να χαράξετε το ίδιο σχήμα, χρησιμοποιήστε το fill_preserve (ή το stroke_preserve), που κρατά τη διαδρομή για μια δεύτερη πράξη:
$cr->arc(100, 100, 40, 0, 6.28318);
$cr->set_source_rgb(0.4, 0.8, 1);
$cr->fill_preserve; # fill, but keep the path
$cr->set_source_rgb(0, 0, 0);
$cr->set_line_width(2);
$cr->stroke; # now outline the same circle
Προπολλαπλασιασμένο άλφα#
Η επιφάνεια argb32 αποθηκεύει pixel με προπολλαπλασιασμένο άλφα: κάθε κανάλι χρώματος είναι ήδη πολλαπλασιασμένο με το άλφα του. Αυτό είναι αόρατο όταν σχεδιάζετε μέσω του API του Cairo, αλλά έχει σημασία τη στιγμή που διαβάζετε ακατέργαστα bytes pixel από την επιφάνεια ή τροφοδοτείτε τον ενταμιευτή του Cairo σε μια άλλη βιβλιοθήκη, γιατί τα bytes δεν είναι το ευθύ RGBA που ίσως υποθέτετε. Όταν διασχίζετε αυτό το όριο, αποπολλαπλασιάστε πρώτα. Μέσα στην ίδια τη σχεδίαση του Cairo δεν προκύπτει ποτέ.
SVG: markup, όχι pixel#
Το SVG είναι καθαρή Perl και κάνει κάτι διαφορετικό: χτίζει ένα έγγραφο XML που περιγράφει σχήματα, και παράγει κείμενο. Τίποτα δεν rasterize· ο καταναλωτής (ένας φυλλομετρητής, το Inkscape, ένας μετατροπέας PDF) το σχεδιάζει. Αυτό το κάνει ιδανικό για έξοδο που πρέπει να παραμείνει ευκρινής σε οποιαδήποτε μεγέθυνση, ή που άλλα εργαλεία θα επεξεργαστούν περαιτέρω.
use SVG;
my $svg = SVG->new(width => 200, height => 200);
# a group carries shared style; children inherit it
my $g = $svg->group(id => 'shapes',
style => { stroke => 'black', fill => 'none' });
$g->line(x1 => 0, y1 => 0, x2 => 200, y2 => 200);
$g->circle(cx => 100, cy => 100, r => 50, style => { fill => 'skyblue' });
$g->rect(x => 10, y => 10, width => 40, height => 40);
$g->path(d => 'M10 190 L100 100 L190 190 Z'); # a triangle via path data
$svg->text(x => 60, y => 110)->cdata('Hello');
print $svg->xmlify;
Το hash στυλ αντιστοιχίζεται στα γνωρίσματα παρουσίασης του SVG: stroke, fill, stroke-width, opacity και τα υπόλοιπα. Ένα group (με ψευδώνυμο g) με ένα στυλ είναι ο τρόπος με τον οποίο αποφεύγετε την επανάληψη γνωρισμάτων σε κάθε στοιχείο· τα παιδιά κληρονομούν και μπορούν να υπερκαλύψουν. Το κείμενο προσαρτάται με ένα αλυσιδωτό cdata γιατί το περιεχόμενο χαρακτήρων είναι ένας κόμβος-παιδί, όχι ένα γνώρισμα.
Για ένα πολύγωνο από υπολογισμένα σημεία, το get_path συναρμολογεί τη συμβολοσειρά σημείων για εσάς:
my @x = (50, 150, 100);
my @y = (10, 10, 90);
my $points = $svg->get_path(x => \@x, y => \@y, -type => 'polygon');
$g->polygon(%$points, style => { fill => 'coral' });
Το xmlify (γράφεται επίσης to_xml ή render) επιστρέφει το ολοκληρωμένο έγγραφο ως συμβολοσειρά. Γράψτε το σε ένα αρχείο .svg και ανοίγει σε οποιονδήποτε φυλλομετρητή· δώστε το σε έναν μετατροπέα για PDF ή PNG.
Cairo ή SVG;#
Θέλετε … | Καταφύγετε σε |
|---|---|
Pixel τώρα, εξομαλυμένα, από συντεταγμένες πραγματικών αριθμών |
|
Έξοδο vector ως αρχείο για φυλλομετρητές ή άλλα εργαλεία |
|
Να αποδώσετε το ίδιο σχέδιο σε PNG, PDF και SVG από ένα API |
|
Καμία μεταγλωττισμένη εξάρτηση καθόλου (καθαρή Perl) |
|
Τα δύο επίσης συνθέτονται: παραγάγετε δομή ως markup SVG, και έπειτα αποδώστε την σε pixel με έναν rasterizer όταν χρειάζεστε ένα bitmap. Για εφαρμοσμένη έξοδο vector στη συγκεκριμένη μορφή διαγραμμάτων και γραφημάτων, και για την ανάγνωση των μεταδεδομένων που βρίσκονται ήδη μέσα σε αρχεία εικόνας, το επόμενο κεφάλαιο καλύπτει τα πραγματιστικά στηρίγματα της δουλειάς raster και vector.