Here’s the most readable way I can think of, which is also reasonably efficient. Say you have an image of dimensions Width
by Height
and desired margins of Left
, Right
, Top
, and Bottom
. Allocate a buffer of Width + Left + Right
by Height + Top + Bottom
filled with zeros. In C++ you can use one of the handy std::vector
constructors:
const auto Channels = 3;
const auto TargetWidth = Width + Left + Right;
const auto TargetHeight = Height + Top + Bottom;
std::vector<uint8_t> target(TargetWidth * TargetHeight * Channels);
The C function calloc()
is also an option. Next, copy each row in the source image to the target image, starting at vertical offset Top
and horizontal offset Left
. Use std::copy()
to copy rows, and run the outer loop in row-major order to avoid cache misses:
for (int y = 0; y < Height; ++y) {
const auto* const source_row = &source[y * Width * Channels];
auto* const target_row = &target[(y + Top) * TargetWidth * Channels + Left];
std::copy(source_row, source_row + Width * Channels, target_row);
}
If you can use 32-bit RGB0 or RGBA instead of 24-bit RGB, you might see faster copying thanks to more consistent alignment, for which std::copy()
or memcpy()
are well optimised. If you can use OpenMP, you might also experiment with parallelising the loop:
#pragma omp parallel for
for (int y = 0; y < Height; ++y) {
// ...
}