【问题标题】:how to create a graphics object using an Atom text editor如何使用 Atom 文本编辑器创建图形对象
【发布时间】:2017-07-15 22:32:15
【问题描述】:

我很难确定在我的编译器中包含 graphics.h 文件的方法。我遇到的所有信息都是针对 IDE 的,例如 CodeBlocks。我希望能够包含图形文件以供使用而不会遇到任何问题。我的问题是:

  1. 您可以使用像 Atom 这样的文本编辑器来创建图形对象吗?
  2. 如果是这样,应该采取哪些步骤来实现这一目标?

【问题讨论】:

  • 你用的是什么编译器?
  • 我下载了MinGW
  • @Sam 你能否在询问“你能使用像 Atom 这样的文本编辑器来创建图形对象吗?”时更精确一点:你指的是使用一个负责处理图形对象还是您要创建图形(例如 perlin 噪声)还是要手动创建图形对象(例如 SVG)?
  • 后两个选项。我明白你的意思。我试图使用图形标准库在图形用户界面中创建图像,但我的问题比这更深。因此,我将修改我的问题,如何在 Atom 中创建图形对象以及 2)如何将类用于此目的?

标签: c++


【解决方案1】:

有许多图形格式具有不同的功能。

我要做的第一个区别是:

光栅图形 vs. 矢量图形

光栅图形(逐像素存储图像)通常采用二进制编码,因为数据量通常与图像大小成正比。然而,其中一些是文本编码的,或者可以是文本编码的,也可以是二进制编码的。

例如:

虽然这些文件格式有点奇怪,但要找到支持它们的软件并不难。例如。 GIMP 支持开箱即用(甚至在 Windows 上)。顺便提一句。就是这么简单,自己写loader和writer也不算太复杂。

可以在我对SO: Convolution for Edge Detection in C 的回复中找到 PPM(Portable anymap 的彩色版本)的简单读写器。

矢量图形(存储构建图像的图形基元)更常见的是文本编码。由于矢量图可以通过简单地对所有坐标应用缩放因子来“无损”缩放到任何图像大小,因此文件大小和目标图像大小没有直接关系。因此,矢量图形是绘图的首选格式,尤其是在需要多种目标分辨率时。

为此,我强烈推荐:

这是(希望)即将推出的 Web 内容中可缩放图形的标准。 Qt 确实为 SVG 提供了(有限的)支持,因此,它是我首选的分辨率无关图标的选择。


一个不同的(但可能相关的)选项是在源代码中嵌入图形。如果您的图像加载器库提供从内存(以及文件)加载图像,则可以使用任何格式来完成此操作。 (我所知道的就是这样做的。) 因此,问题可以简化为:如何在 C/C++ 源代码中嵌入大量(ASCII 或二进制)数据作为常量?恕我直言,这很容易解决。

我在回答 SO: Paint a rect on qglwidget at specifit times 时这样做了。


更新:

当我注意到 PPM 的链接示例(以及 PBM 的另一个示例)实际上读取二进制格式时,我实现了一个示例应用程序来演示 ASCII PPM 的用法。

我相信 XPM 更适合在文本编辑器中可编辑的特定要求。因此,我也在我的示例中考虑了这一点。

由于问题没有提到需要什么特定的内部图像格式,也没有提到它应该在什么 API 中可用,所以我选择了 Qt

  • 是我熟悉的东西
  • 提供一个 QImage,用作图像导入的目标
  • 只需几行代码即可直观地输出结果。

源码test-QShowPPM-XPM.cc:

// standard C++ header:
#include <cassert>
#include <iostream>
#include <string>
#include <sstream>

// Qt header:
#include <QtWidgets>

// sample image in ASCII PPM format
// (taken from https://en.wikipedia.org/wiki/Netpbm_format)
const char ppmData[] =
"P3\n"
"3 2\n"
"255\n"
"255   0   0     0 255   0     0   0 255\n"
"255 255   0   255 255 255     0   0   0\n";

// sample image in XPM3 format
/* XPM */
const char *xpmData[] = {
  // w, h, nC, cPP
  "16 16 5 1",
  // colors
  "  c #ffffff",
  "# c #000000",
  "g c #ffff00",
  "r c #ff0000",
  "b c #0000ff",
  // pixels
  "       ##       ",
  "    ###gg###    ",
  "   #gggggggg#   ",
  "  #gggggggggg#  ",
  " #ggbbggggbbgg# ",
  " #ggbbggggbbgg# ",
  " #gggggggggggg# ",
  "#gggggggggggggg#",
  "#ggrrggggggrrgg#",
  " #ggrrrrrrrrgg# ",
  " #ggggrrrrgggg# ",
  " #gggggggggggg# ",
  "  #gggggggggg#  ",
  "   #gggggggg#   ",
  "    ###gg###    ",
  "       ##       "
};

// Simplified PPM ASCII Reader (no support of comments)

inline int clamp(int value, int min, int max)
{
  return value < min ? min : value > max ? max : value;
}

inline int scale(int value, int maxOld, int maxNew)
{
  return value * maxNew / maxOld;
}

QImage readPPM(std::istream &in)
{
  std::string header;
  std::getline(in, header);
  if (header != "P3") throw "ERROR! Not a PPM ASCII file.";
  int w = 0, h = 0, max = 255; // width, height, bits per component
  if (!(in >> w >> h >> max)) throw "ERROR! Premature end of file.";
  if (max <= 0 || max > 255) throw "ERROR! Invalid format.";
  QImage qImg(w, h, QImage::Format_RGB32);
  for (int y = 0; y < h; ++y) {
    for (int x = 0; x < w; ++x) {
      int r, g, b;
      if (!(in >> r >> g >> b)) throw "ERROR! Premature end of file.";
      qImg.setPixel(x, y,
          scale(clamp(r, 0, 255), max, 255) << 16
        | scale(clamp(g, 0, 255), max, 255) << 8
        | scale(clamp(b, 0, 255), max, 255));
    }
  }
  return qImg;
}

// Simplified XPM Reader (implements sub-set of XPM3)

char getChar(const char *&p)
{
  if (!*p) throw "ERROR! Premature end of file.";
  return *p++;
}

std::string getString(const char *&p)
{
  std::string str;
  while (*p && !isspace(*p)) str += *p++;
  return str;
}

void skipWS(const char *&p)
{
  while (*p && isspace(*p)) ++p;
}

QImage readXPM(const char **xpmData)
{
  int w = 0, h = 0; // width, height
  int nC = 0, cPP = 1; // number of colors, chars per pixel
  { std::istringstream in(*xpmData);
    if (!(in >> w >> h >> nC >> cPP)) throw "ERROR! Premature end of file.";
    ++xpmData;
  }
  std::map<std::string, std::string> colTbl;
  for (int i = nC; i--; ++xpmData) {
    const char *p = *xpmData;
    std::string chr;
    for (int j = cPP; j--;) chr += getChar(p);
    skipWS(p);
    if (getChar(p) != 'c') throw "ERROR! Format not supported.";
    skipWS(p);
    colTbl[chr] = getString(p);
  }
  QImage qImg(w, h, QImage::Format_RGB32);
  for (int y = 0; y < h; ++y, ++xpmData) {
    const char *p = *xpmData;
    for (int x = 0; x < w; ++x) {
      std::string pixel;
      for (int j = cPP; j--;) pixel += getChar(p);
      qImg.setPixelColor(x, y, QColor(colTbl[pixel].c_str()));
    }
  }
  return qImg;
}

// a customized QLabel to handle scaling
class LabelImage: public QLabel {

  private:
    QPixmap _qPixmap, _qPixmapScaled;

  public:
    LabelImage();
    LabelImage(const QPixmap &qPixmap): LabelImage()
    {
      setPixmap(qPixmap);
    }
    LabelImage(const QImage &qImg): LabelImage(QPixmap::fromImage(qImg))
    { }

    void setPixmap(const QPixmap &qPixmap) { setPixmap(qPixmap, size()); }

  protected:
    virtual void resizeEvent(QResizeEvent *pQEvent);

  private:
    void setPixmap(const QPixmap &qPixmap, const QSize &size);
};

// main function
int main(int argc, char **argv)
{
  qDebug() << QT_VERSION_STR;
  // main application
#undef qApp // undef macro qApp out of the way
  QApplication qApp(argc, argv);
  // setup GUI
  QMainWindow qWin;
  QGroupBox qBox;
  QGridLayout qGrid;
  LabelImage qLblImgPPM(readPPM(std::istringstream(ppmData)));
  qGrid.addWidget(&qLblImgPPM, 0, 0, Qt::AlignCenter);
  LabelImage qLblImgXPM(readXPM(xpmData));
  qGrid.addWidget(&qLblImgXPM, 1, 0, Qt::AlignCenter);
  qBox.setLayout(&qGrid);
  qWin.setCentralWidget(&qBox);
  qWin.show();
  // run application
  return qApp.exec();
}

// implementation of LabelImage

LabelImage::LabelImage(): QLabel()
{
  setFrameStyle(Raised | Box);
  setAlignment(Qt::AlignCenter);
  //setMinimumSize(QSize(1, 1)); // seems to be not necessary
  setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
}

void LabelImage::resizeEvent(QResizeEvent *pQEvent)
{
  QLabel::resizeEvent(pQEvent);
  setPixmap(_qPixmap, pQEvent->size());
}

void LabelImage::setPixmap(const QPixmap &qPixmap, const QSize &size)
{
  _qPixmap = qPixmap;
  _qPixmapScaled = _qPixmap.scaled(size, Qt::KeepAspectRatio);
  QLabel::setPixmap(_qPixmapScaled);
}

这是在VS2013中编译并在Windows 10(64位)中测试的:

【讨论】:

  • 感谢您的帮助。我去看看
  • @Sam 我添加了一个示例应用程序。请注意,这些不是功能齐全的阅读器,无法减少必要的示例代码行数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-23
  • 2017-09-21
相关资源
最近更新 更多