1 /*
2  * mp3plot - Bitrate analysis tool
3  *
4  * Copyright (C) 2007, 2009 Toni Corvera
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 // $Id: gd_plotter.cc 1213 2009-04-24 20:18:17Z  $
22 
23 #include "../mp3_config.h"                 // Defines HAVE_GD / DISABLE_GD / DISABLE_GRAPHICS
24 
25 #if defined(HAVE_GD) && !defined(DISABLE_GRAPHICS) && !defined(DISABLE_GD)
26 
27 #include <string>
28 #include <cassert>
29 #include <fstream>
30 
31 #include "../common.h"
32 #include "../utils/logger.h"
33 #include "../mp3/bitrate.h"
34 #include "../mp3/frame.h"
35 #include "colour.h"
36 #include "gd_plotter.h"
37 #include "gd_image.h"
38 
39 namespace {
40 
41     using mp3plot::numframes_t;
42     using mp3plot::gd_image;
43     using mp3plot::graphics_lib_interface;
44 
45     namespace gd = mp3plot::gdlib;
46 
47     // This is pretty much redundant...
48      struct gd_interface : public graphics_lib_interface<gd::image, gd::colour> {
gd_interface__anonbe3f2ef10111::gd_interface49         gd_interface()
50             : cached_bordercol(0)
51         {}
52 
~gd_interface__anonbe3f2ef10111::gd_interface53         virtual ~gd_interface() {
54             delete cached_bordercol;
55         }
create_image__anonbe3f2ef10111::gd_interface56         virtual image_type create_image(int w, int h) const {
57             return gd_image(w, h, gd::rgb24b_colour(0xff));
58         }
59 
resize__anonbe3f2ef10111::gd_interface60         virtual void resize(image_type & im, int w, int h) const {
61             im.resize(w, h);
62         }
63 
vertical_merge__anonbe3f2ef10111::gd_interface64         virtual image_type vertical_merge(const image_type& top, const image_type& bottom) const {
65             return gd_image::vmerge(top, bottom);
66         }
67 
allocate_colour__anonbe3f2ef10111::gd_interface68         virtual native_colour allocate_colour(image_type& im,
69                                               const common_colour& c) const {
70             return im.allocate_colour(c);
71         }
72 
draw_line__anonbe3f2ef10111::gd_interface73         virtual void draw_line(image_type & im,
74                                int x0, int y0, int x1, int y1,
75                                const native_colour & c) const
76         {
77             im.line(x0, y0, x1, y1, c);
78         }
79 
draw_rectangle__anonbe3f2ef10111::gd_interface80         virtual void draw_rectangle(image_type& im,
81                                     int x0, int y0, int x1, int y1,
82                                     const native_colour& c) const
83         {
84             // Order is not important:
85             //assert( x0 < x1 );
86             //assert( y0 < y1 );
87             // Empty rectangle:
88             if (x0 == x1 && y0 == y1) { return; }
89             // "negative" rectangle
90             if (x0+1 >= x1-1 || y0+1 >= y1-1) { return; }
91 
92             if (0 != cached_bordercol) {
93                 if (cached_bordercol->first != &im) {
94                     delete cached_bordercol;
95                     cached_bordercol = 0;
96                 }
97             }
98             if (0 == cached_bordercol) {
99                 const int col = im.allocate_colour(gd::rgb24b_colour(0));
100                 cached_bordercol = new std::pair<gd_image*,int>(&im, col);
101             }
102             assert( 0 != cached_bordercol );
103             assert( &im == cached_bordercol->first );
104             const int black = cached_bordercol->second;
105             im.rectangle(x0, y0, x1, y1, black, false);
106             im.rectangle(x0+1, y0+1, x1-1, y1-1, c, true);
107         }
108 
109         // In GD, the coordinates are those of the top-left corner
draw_text__anonbe3f2ef10111::gd_interface110         virtual void draw_text(image_type& im,
111                                int x, int y,
112                                const native_colour & c,
113                                const std::string & label) const
114         {
115             const int tw = im.get_font_width() * label.length();
116             im.text(x-(tw/2), y-(im.get_font_height()/2), c, label);
117         }
118     private:
119         mutable std::pair<gd_image*, int> * cached_bordercol;
120     };
121 
122 } // anonymous namespace
123 
124 namespace mp3plot {
125 
plot(const mp3file & file,const plot_params & params) const126 void gd_plotter::plot(const mp3file & file, const plot_params& params) const
127     throw (e_error)
128 {
129     assert( !params.output_filename.empty() );
130 
131     using namespace std;
132     net_outlyer::logger::os() << "Using the GD output module\n";
133 
134     try {
135         const gd_image im = image_plotter::plot<gdlib::image, gdlib::colour>(file.get_frames(), gd_interface(), params);
136         std::ofstream ofs( params.output_filename.c_str(), ios::out|ios::binary );
137         ofs << im;
138         ofs.close();
139     }
140     catch (const e_error & e) {
141         // Only gd_image() throws
142         throw e_error("Failed to create images in memory.", EX_UNAVAILABLE);
143     }
144 } // gd_plotter::plot()
145 
146 
147 } // namespace mp3plot
148 
149 #endif // DISABLE_GRAPHICS, DISABLE_GD
150 
151 // vim:set ts=4 et ai:
152 
153