Cleanup and new features in Image code. (#685)

- Removes stride_, since we know for a fact that it is always width * 4.
- Adds a constructor from a cairo surface.
- Adds a function that rotates the image by 90 degrees.

This is in preparation of adding a tool that can generate an image from a .pbstream.
master
Holger Rapp 2017-11-16 17:05:18 +01:00 committed by Wally B. Feed
parent 0b4e7a9443
commit 5ee830e8cc
2 changed files with 36 additions and 11 deletions

View File

@ -31,10 +31,9 @@ cairo_status_t CairoWriteCallback(void* const closure,
return CAIRO_STATUS_WRITE_ERROR;
}
int StrideForWidth(int width) {
void CheckStrideIsAsExpected(int width) {
const int stride = cairo_format_stride_for_width(kCairoFormat, width);
CHECK_EQ(stride % 4, 0);
return stride;
CHECK_EQ(stride, width * 4);
}
} // namespace
@ -48,10 +47,33 @@ UniqueCairoPtr MakeUniqueCairoPtr(cairo_t* surface) {
}
Image::Image(int width, int height)
: width_(width),
height_(height),
stride_(StrideForWidth(width)),
pixels_(stride_ / 4 * height, 0) {}
: width_(width), height_(height), pixels_(width * height, 0) {}
Image::Image(UniqueCairoSurfacePtr surface)
: width_(cairo_image_surface_get_width(surface.get())),
height_(cairo_image_surface_get_height(surface.get())) {
CHECK_EQ(cairo_image_surface_get_format(surface.get()), kCairoFormat);
CheckStrideIsAsExpected(width_);
const uint32* pixel_data =
reinterpret_cast<uint32*>(cairo_image_surface_get_data(surface.get()));
const int num_pixels = width_ * height_;
pixels_.reserve(num_pixels);
for (int i = 0; i < num_pixels; ++i) {
pixels_.push_back(pixel_data[i]);
}
}
void Image::Rotate90DegreesClockwise() {
const auto old_pixels = pixels_;
pixels_.clear();
for (int x = 0; x < width_; ++x) {
for (int y = height_ - 1; y >= 0; --y) {
pixels_.push_back(old_pixels.at(y * width_ + x));
}
}
std::swap(width_, height_);
}
void Image::WritePng(FileWriter* const file_writer) {
// TODO(hrapp): cairo_image_surface_create_for_data does not take ownership of
@ -67,17 +89,17 @@ void Image::WritePng(FileWriter* const file_writer) {
}
const Uint8Color Image::GetPixel(int x, int y) const {
return CairoToUint8Color(pixels_[y * stride_ / 4 + x]);
return CairoToUint8Color(pixels_[y * width_ + x]);
}
void Image::SetPixel(int x, int y, const Uint8Color& color) {
pixels_[y * stride_ / 4 + x] = Uint8ColorToCairo(color);
pixels_[y * width_ + x] = Uint8ColorToCairo(color);
}
UniqueCairoSurfacePtr Image::GetCairoSurface() {
return MakeUniqueCairoSurfacePtr(cairo_image_surface_create_for_data(
reinterpret_cast<unsigned char*>(pixels_.data()), kCairoFormat, width_,
height_, stride_));
height_, width_ * 4 /* stride */));
}
} // namespace io

View File

@ -48,12 +48,16 @@ UniqueCairoPtr MakeUniqueCairoPtr(cairo_t* surface);
class Image {
public:
explicit Image(UniqueCairoSurfacePtr surface);
Image(int width, int height);
const Uint8Color GetPixel(int x, int y) const;
void SetPixel(int x, int y, const Uint8Color& color);
void WritePng(FileWriter* const file_writer);
// Rotates the image in place.
void Rotate90DegreesClockwise();
// Returns a pointer to a cairo surface that contains the current pixel data.
// The 'Image' object must therefore outlive the returned surface object. It
// is undefined behavior to call any of the mutating functions while a pointer
@ -66,7 +70,6 @@ class Image {
private:
int width_;
int height_;
int stride_;
std::vector<uint32> pixels_;
};