Commit ee7a3410 authored by Paul Asmuth's avatar Paul Asmuth
Browse files

add Image class and Layer::pixmap member

parent 691e3e9a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -19,9 +19,9 @@ add_library(signaltk STATIC
    src/signaltk/core/path.cc
    src/signaltk/core/brush.cc
    src/signaltk/core/colour.cc
    src/signaltk/core/image.cc
    src/signaltk/core/layer.cc
    src/signaltk/core/text.cc
    src/signaltk/core/image_api.cc
    src/signaltk/core/rasterize.cc
    src/signaltk/plot/gridlines.cc
    src/signaltk/plot/axes.cc
+2 −1
Original line number Diff line number Diff line
@@ -21,7 +21,8 @@ struct Context {
enum Status : int {
  OK,
  ERROR,
  ERROR_NOT_IMPLEMENTED
  ERROR_NOT_IMPLEMENTED,
  ERROR_INVALID_ARGUMENT
};

struct Command {
+215 −0
Original line number Diff line number Diff line
/**
 * This file is part of the "signaltk" project
 *   Copyright (c) 2017 Paul Asmuth
 *
 * signaltk is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <assert.h>
#include <string.h>
#include "image.h"

namespace signaltk {

Image::Image(
    PixelFormat pixel_format,
    size_t width,
    size_t height) :
    pixel_format_(pixel_format),
    width_(width),
    height_(height),
    pixmap_(nullptr) {
  auto pixmap_size = width_ * height_ * getPixelSize();
  pixmap_ = malloc(pixmap_size);
  if (!pixmap_) {
    throw std::bad_alloc(); // FIXME?
  }
}

Image::Image(
    Image&& other) :
    pixel_format_(other.pixel_format_),
    width_(other.width_),
    height_(other.height_),
    pixmap_(other.pixmap_) {
  other.width_ = 0;
  other.height_ = 0;
  other.pixmap_ = nullptr;
}

Image::~Image() {
  if (pixmap_) {
    free(pixmap_);
  }
}

PixelFormat Image::getPixelFormat() const {
  return pixel_format_;
}

size_t Image::getPixelCount() const {
  return width_ * height_;
}

size_t Image::getPixelSize() const {
  return signaltk::getPixelSize(pixel_format_);
}

size_t Image::getWidth() const {
  return width_;
}

size_t Image::getHeight() const {
  return height_;
}

const void* Image::getData() const {
  return pixmap_;
}

void* Image::getData() {
  return pixmap_;
}

size_t Image::getDataSize() const {
  return width_ * height_ * getPixelSize();
}

Colour Image::getPixel(size_t x, size_t y) {
  return getPixel(y * width_ + x);
}

Colour Image::getPixel(size_t idx) {
  assert(idx < width_ * height_);

  auto pixel_size = getPixelSize();
  return decodePixel(
      pixel_format_,
      static_cast<char*>(pixmap_) + idx * pixel_size,
      pixel_size);
}

void Image::setPixel(size_t x, size_t y, const Colour& colour) {
  return setPixel(y * width_ + x, colour);
}

void Image::setPixel(size_t idx, const Colour& colour) {
  assert(idx < width_ * height_);

  auto pixel_size = getPixelSize();
  encodePixel(
      pixel_format_,
      colour,
      static_cast<char*>(pixmap_) + idx * pixel_size,
      pixel_size);
}

void Image::clear(const Colour& colour) {
  auto pixel_size = getPixelSize();
  for (size_t i = 0; i < width_ * height_; ++i) {
    encodePixel(
        pixel_format_,
        colour,
        static_cast<char*>(pixmap_) + i * pixel_size,
        pixel_size);
  }
}

size_t getPixelSize(PixelFormat pixel_format) {
  switch (pixel_format) {

    case PixelFormat::RGB8:
      return 3;

    case PixelFormat::RGBA8:
      return 4;

    default:
      return 0;

  }
}

void encodePixel_RGBA8(
    const Colour& colour,
    char* data,
    size_t size) {
  assert(size >= 4);
  data[0] = colour[0] * 255;
  data[1] = colour[1] * 255;
  data[2] = colour[2] * 255;
  data[3] = colour[3] * 255;
}

void encodePixel(
    PixelFormat pixel_format,
    const Colour& colour,
    char* data,
    size_t size) {
  switch (pixel_format) {

    case PixelFormat::RGBA8:
      return encodePixel_RGBA8(colour, data, size);

    default:
      return;

  }
}

Colour decodePixel_RGBA8(
    char* data,
    size_t size) {
  assert(size >= 4);
  Colour c;
  c[0] = data[0] / 255.0f;
  c[1] = data[1] / 255.0f;
  c[2] = data[2] / 255.0f;
  c[3] = data[3] / 255.0f;
  return c;
}

Colour decodePixel(
    PixelFormat pixel_format,
    char* data,
    size_t size) {
  switch (pixel_format) {

    case PixelFormat::RGBA8:
      return decodePixel_RGBA8(data, size);

    default:
      return Colour{};

  }
}

Image convertImage_RGB8_RGBA8(const Image& img) {
  Image newimg(PixelFormat::RGBA8, img.getWidth(), img.getHeight());

  auto src = ((const unsigned char*) img.getData());
  auto dst = ((unsigned char*) newimg.getData());
  for (size_t i = 0; i < img.getWidth() * img.getHeight(); ++i) {
    memcpy(dst + i * 4, src + i * 3, 3); 
    dst[i * 4 + 3] = 0xff;
  }

  return newimg;
}

Image convertImage_RGB8A_RGB8(const Image& img) {
  Image newimg(PixelFormat::RGB8, img.getWidth(), img.getHeight());

  auto src = ((const unsigned char*) img.getData());
  auto dst = ((unsigned char*) newimg.getData());
  for (size_t i = 0; i < img.getWidth() * img.getHeight(); ++i) {
    memcpy(dst + i * 3, src + i * 4, 3); 
  }

  return newimg;
}

} // namespace signaltk
+55 −39
Original line number Diff line number Diff line
/**
 * This file is part of the "signaltk" project
 *   Copyright (c) 2018 Paul Asmuth
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *   Copyright (c) 2017 Paul Asmuth
 *
 * libstx is free software: you can redistribute it and/or modify it under
 * signaltk is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#ifndef _libstx_Image_H
#define _libstx_Image_H
#pragma once
#include <stdlib.h>
#include <vector>
#include <string>
#include <vector>
#include "colour.h"
#include "path.h"
#include "brush.h"

namespace signaltk {
namespace chart {

enum class PixelFormat {
  RGB8, RGBA8
};

class Image {
public:
  virtual ~Image() {}

  virtual void drawText(
      const std::string& text,
      double x,
      double y,
      const std::string& halign,
      const std::string& valign,
      const std::string& class_name,
      double rotate = 0.0f) = 0;

  virtual void strokePath(
      const PathData* point_data,
      size_t point_count,
      const StrokeStyle& style) = 0;

  void strokeLine(
      double x1,
      double y1,
      double x2,
      double y2,
      const StrokeStyle& style) {
    Path p;
    p.moveTo(x1, y1);
    p.lineTo(x2, y2);
    strokePath(p.data(), p.size(), style);
  }

  Image(
      PixelFormat pixel_format,
      size_t width,
      size_t height);

  ~Image();
  Image(const Image& other) = delete;
  Image(Image&& other);
  Image& operator=(const Image& other) = delete;

  PixelFormat getPixelFormat() const;
  size_t getPixelSize() const;
  size_t getPixelCount() const;
  size_t getWidth() const;
  size_t getHeight() const;
  const void* getData() const;
  void* getData();
  size_t getDataSize() const;

  Colour getPixel(size_t x, size_t y);
  Colour getPixel(size_t idx);
  void setPixel(size_t x, size_t y, const Colour& colour);
  void setPixel(size_t idx, const Colour& colour);
  void clear(const Colour& colour);

protected:
  PixelFormat pixel_format_;
  size_t width_;
  size_t height_;
  void* pixmap_;
};

Image convertImage_RGB8_RGBA8(const Image& img);
Image convertImage_RGBA8_RGB8(const Image& img);

size_t getPixelSize(PixelFormat pixel_format);

void encodePixel(
    PixelFormat pixel_format,
    const Colour& colour,
    char* data,
    size_t size);

Colour decodePixel(
    PixelFormat pixel_format,
    char* data,
    size_t size);

} // namespace signaltk
}
}
#endif

src/signaltk/core/image_api.cc

deleted100644 → 0
+0 −54
Original line number Diff line number Diff line
/**
 * This file is part of the "signaltk" project
 *   Copyright (c) 2018 Paul Asmuth
 *
 * libstx is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <iostream>
#include <signaltk/util/flagparser.h>
#include "image_api.h"

namespace signaltk {

int cmd_image_new(Context* ctx, const char** args, int arg_count) {
  FlagParser flag_parser;

  std::string flag_out;
  flag_parser.defineString("out", true, &flag_out);

  uint64_t flag_width;
  flag_parser.defineUInt64("width", true, &flag_width);

  uint64_t flag_height;
  flag_parser.defineUInt64("height", true, &flag_height);

  std::string flag_clear;
  flag_parser.defineString("clear", true, &flag_clear);

  auto rc = flag_parser.parseArgv(arg_count, args);
  if (!rc.isSuccess()) {
    std::cerr << "ERROR: " << rc.getMessage() << std::endl;
    return -1;
  }

  Layer target(flag_width, flag_height);

  if (!flag_clear.empty()) {
    Colour clear_colour;
    if (!clear_colour.parse(flag_clear)) {
      return -1; // FIXME error
    }

    target.clear(clear_colour);
  }

  target.writePNG(flag_out.c_str());

  return 0;
}

} // namespace signaltk
Loading