用 C++ 和 libgd 来绘图

用 C++ 和 libgd 来绘图

[TOC]

旧文转贴, 代码很久以前写的, 大约至今有十年了, 最近看到有人问如何用 C++ 来生成图表.
有一个 graphviz 的开源库可以用, 它用了自己的领域特定语言 DSL: dot 来生成图表, 具体应用可见 http://graphviz.org/

当然也可以不用这么重的开源库, 这里介绍了以前写的一个chart 库, 几百行代码, 采用了比较原始的作法, 调用了 libgd 基础API, 如画点, 画线等原子方法来绘制图表, 可以应用于一些比较简单的场合

实例

先看看生成的图表实例

折线图和鱼骨头图

用 C++ 和 libgd 来绘图_第1张图片
这里写图片描述

圆饼图和直方图

用 C++ 和 libgd 来绘图_第2张图片
这里写图片描述

示例代码

上面两个图表由以下几十行代码来实现

#include "TinyUtil.h"
#include "TinyChart.h"
#include 
#include 
#include 
#include 


int main(int argc, char **argv)
{
    printf("-- write image by gd ---");
    {
        STR_VEC xScales;
        xScales.reserve(10);
        xScales.push_back("11-09");
        xScales.push_back("11-10");
        xScales.push_back("11-11");
        xScales.push_back("11-12");
        xScales.push_back("11-13");
        xScales.push_back("11-14");
        xScales.push_back("11-15");
        xScales.push_back("11-16");
        xScales.push_back("11-17");
        xScales.push_back("11-18");
        xScales.push_back("11-19");
        xScales.push_back("11-20");
        xScales.push_back("11-21");
        xScales.push_back("11-22");

        INT_VEC yScales;
        yScales.reserve(10);
        yScales.push_back(200);
        yScales.push_back(130);
        yScales.push_back(3456);
        yScales.push_back(2345);
        yScales.push_back(1320);
        yScales.push_back(30);
        yScales.push_back(2200);
        yScales.push_back(1330);
        yScales.push_back(3330);
        yScales.push_back(332);
        yScales.push_back(788);
        yScales.push_back(200);
        yScales.push_back(13890);
        yScales.push_back(200);

        TinyTrendlineDiagram* pt = new TinyTrendlineDiagram(
                "latency_trendline.png", 800, 250);
        pt->SetTitle("Trend of Latency (the middle network latency is the value of 0 coordinate)");
        pt->SetLabels(xScales);
        pt->SetValues(yScales);

        pt->Draw();
        pt->WriteImage();
        delete pt;
    }

    {
        STR_VEC xScales;
        xScales.push_back("America");
        xScales.push_back("China");
        xScales.push_back("Japan");
        xScales.push_back("England");
        xScales.push_back("France");
        xScales.push_back("Germany");
        xScales.push_back("South Korean");
        xScales.push_back("India");

        INT_VEC yScales;
        yScales.push_back(4800);
        yScales.push_back(3008);
        yScales.push_back(100);
        yScales.push_back(20);
        yScales.push_back(2000);
        yScales.push_back(178);
        yScales.push_back(258);
        yScales.push_back(1789);

        TinyDistributionDiagram* pd = new TinyDistributionDiagram(
                "users_distribution.png", 800, 600);
        pd->SetTitle("Daily active users distribution among the countries");
        pd->SetLabels(xScales);
        pd->SetValues(yScales);
        pd->Draw();
        pd->WriteImage();
        delete pd;
    }
    return 0;
}

�设计与实现

其实, 也就是封装了libgd 的原子操作, 绘制了基本的图形单元

�1) 首先下载并编译依赖库 libgd

  • 下载: Download libgd-2.2.1.tar.gz
  • 解压: tar xvfz libgd-2.2.1.tar.gz
  • 构建步骤 build steps
    cd libgd-2.2.1
    mkdir bld
    cd bld
    cmake -DENABLE_PNG=1 -DENABLE_JPEG=1 -DENABLE_FREETYPE=1 ..
    make
    make install
  1. 然后实现上图所示的类, 加上测试, 约有千余行代码, 放在 github 里

https://gist.github.com/walterfan/b7200fd3e5315ec1e16551fca096a67e

附以上类图的源码, 由 http://yuml.me 生成

// Cool Class Diagram
[Sharp]^[Arc]
[Arc]^[Eclipse]
[Arc]^[Circle]
[Sharp]^[Rectangle]
[Sharp]^[Scale]
[Sharp]^[Chart]
[Chart]^[CurveChart]
[Chart]^[ColumnChart]
[Chart]^[PieChart]
[Chart]^[HistogramChart]
[Diagram]-[note:Aggregate chart{bg:wheat}]
[Diagram]^[DistributionDiagram]
[Diagram]^[TrendlineDiagram]
[TrendlineDiagram]<>-0..*>[CurveChart]
[TrendlineDiagram]<>-0..*>[ColumnChart]
[DistributionDiagram]<>-0..*>[PieChart]
[DistributionDiagram]<>-0..*>[HistogramChart]

接口如下, 代码比较老, 欢迎指正


#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 

#include "gd.h"
#include "gdfonts.h"
#include "gdfontt.h"

using namespace std;  

#define TinyPoint gdPoint
#define TinyFont gdFont
#define TinyColor int
#define WHITE 255,255,255
#define BLACK 0,0,0
#define GRAY 192,192,192
#define RED 255,0,0
#define GREEN 0,255,0
#define BLUE 0,0,255
#define MAGENTA 255,0,255
#define CYAN 0,255,255
#define YELLOW 255,255,0
#define AZURY 153,153,255
#define ORANGE_RED  255,36,00

#define PI 3.14159265357989

#ifdef NDEBUG
#define TRACE(msg)
#else
#define TRACE(msg)  cout<<__FILE__<<", "<<__LINE__<<": "<, allocator > STR2INT_MAP;
typedef vector > INT_VEC;
typedef vector > STR_VEC;

const int NAMESIZE=256;
const int DAYS=14;

class TinyShape
{
public:
    TinyShape(gdImagePtr im)
    {
        m_pImage=im;
        m_nBorderWidth=1;
        SetBgColor(WHITE);
        SetFrColor(BLACK);
        SetBorderColor(BLACK);
        m_nBorderWidth=1;
    };
    void SetBgColor(int r,int g,int b)
    {
        m_BgColor=gdImageColorAllocate(m_pImage, r, g, b);
    };
    void SetFrColor(int r,int g,int b)
    {
        m_FrColor=gdImageColorAllocate(m_pImage, r, g, b);
    };

    void SetBorderColor(int r,int g,int b)
    {
        m_BorderColor=gdImageColorAllocate(m_pImage, r, g, b);
    };
    void SetBgColor(TinyColor color)
    {
        m_BgColor=color;
    };
    TinyColor GetBgColor()
    {
        return m_BgColor;
    };
    TinyColor GetBorderColor()
    {
        return m_BorderColor;
    };
    void SetFrColor(TinyColor color)
    {
        m_FrColor=color;
    };

    void SetBorderColor(TinyColor color)
    {
        m_BorderColor=color;
    };
    void SetBorderWidth(int w)
    {
        m_nBorderWidth=w;
    };
    virtual ~TinyShape()
    {
        m_pImage=NULL;
    };
    virtual void Draw() = 0;

    virtual void Fill() { };
protected:
    int m_nBorderWidth;
    gdImagePtr m_pImage;
    TinyColor m_BorderColor;
    TinyColor m_BgColor;
    TinyColor m_FrColor;
};

class TinyScale:public TinyShape
{
public:
    TinyScale(gdImagePtr im,TinyColor color):TinyShape(im)
    {
        m_FrColor=color;
        m_pFont=gdFontSmall;//gdFontTiny
        m_TopLeftPoint.x=0;
        m_TopLeftPoint.y=0;
        m_OffsetPoint.x=0;
        m_OffsetPoint.y=0;

    };
    void Draw()
    {
        gdImageString(m_pImage, m_pFont, m_TopLeftPoint.x+m_OffsetPoint.x, m_TopLeftPoint.y+m_OffsetPoint.y, (unsigned char*)m_text, m_FrColor);
    };
    void Draw(char * text)
    {
        TRACE(" TinyScale:Draw(char * text): " < m_Shapes;
    vector m_xScale;
    vector m_yScale;
    int m_nVerticalScale;
    int m_nHorziontalScale;
};

class TinyCurveChart:public TinyChart
{
public:
    void Plot();
    //void SetData();
    void SetVerticalScale(INT_VEC& vecYScale);
    //void SetHorziontalScale(STR_VEC& vecXScale,int nXScale){};
    TinyCurveChart(gdImagePtr im):TinyChart(im)
    {
        SetFrColor(RED);
    };
    virtual ~TinyCurveChart()
    {};
    void DrawTitle(){};
};

class TinyColumnChart:public TinyChart
{
public:
    void Plot();
    void SetVerticalScale(INT_VEC& vecYScale);
    //void SetHorziontalScale(STR_VEC& vecXScale,int nXScale){};
    TinyColumnChart(gdImagePtr im):TinyChart(im)
    {};
    virtual ~TinyColumnChart()
    {};
};
class TinyHistogram:public TinyChart
{
public:
    void Plot();
    void SetHorziontalScale(STR_VEC& vecXScale);
    void SetVerticalScale(INT_VEC& vecYScale);
    //void SetHorziontalScale(STR_VEC& vecXScale,int nXScale){};
    TinyHistogram(gdImagePtr im):TinyChart(im)
    {};
    virtual ~TinyHistogram()
    {};
};

class TinyPieChart:public TinyChart
{
public:
    void Draw();
    void DrawLegend();
    void DrawFrame();
    void Plot();
    void SetHorziontalScale(STR_VEC& vecXScale);
    void SetVerticalScale(INT_VEC& vecYScale);
    TinyColor GetRandColor(int index=-1);
    TinyPieChart(gdImagePtr im):TinyChart(im), m_nSum(0)
    {

    };
    virtual ~TinyPieChart()
    {};
private:
    int m_nSum;
};
class TinyDiagram
{

public:

    TinyDiagram(const char* filename,int width,int height);
    virtual ~TinyDiagram();

    int SetFileName(const char* szFilename);

    int SetTitle(const char* szTitle);

    virtual void Draw() {};

    void DrawBorder();

    void SetLabels(STR_VEC& xScales);

    void SetValues(INT_VEC& yScales);

    gdImagePtr GetImage()
    {
        return m_pImage;
    };
    void WriteImage();
protected:
    gdImagePtr m_pImage;

    int m_nWidth;
    int m_nHeight;

    char m_szFileName[NAMESIZE];
    char m_szTitle[NAMESIZE];

    INT_VEC m_vecData;
    STR_VEC m_vecName;
};

class TinyTrendlineDiagram:public TinyDiagram
{
public:
    TinyCurveChart* m_pCurveChart;
    TinyColumnChart* m_pColumnChart;

    TinyTrendlineDiagram(const char* filename,int width,int height);
    virtual ~TinyTrendlineDiagram();
    void Draw();
};

class TinyDistributionDiagram:public TinyDiagram
{
public:
    TinyPieChart* m_pPieChart;
    TinyHistogram* m_pHistogram;
    void Draw();
    TinyDistributionDiagram(const char* filename,int width,int height);
    virtual ~TinyDistributionDiagram();

};


#endif /* UTIL_TINYCHART_H_ */

你可能感兴趣的:(用 C++ 和 libgd 来绘图)