только если подняться на высокий уровень (С++).
Код:

// это чтобы можно было легко подменить тип-носитель
// для "цвета" ячейки
typedef int surf_bit_t;
struct rect_t
{
// прямоугольник - понадобится для пересечений
int left, top, right, bottom;
}
// стркуктура, которая указывает, в каком виде хранится картинка.
// данные хранятся в виде линейного массива определённой ширины строчки
// на картинке нарисован массив, у которого stride = 6,
// x x x x x x width = 4, height = 3. Можно сказать, что мы работаем
// x x 1 1 1 1 с большим массивом 6x5, а можно что с
// x x 1 0 0 0 1 1 1 1 ? ? маленьким 4x3, строчки которого
// x x 1 0 0 0 1 0 0 0 ? ? расположены через 6 элементов.
// x x x x x x 1 0 0 0 ? ? begin в последнем случае указывает на
// начало "маленького" массива.
struct surface_desc
{
surf_bit_t *begin; // начало данных
unsigned width, height, stride; // длина, ширина блока, длина строчки
};
void __blt(surface_desc* from, surface_desc* to)
{
// функция НЕ ПОЗВОЛЯЕТ копировать в себя, то есть когда from и to могут пересекаться.
// копирование без проверки исходых данных.
// чтобы случайно не попортить память при записи, руководствуемся размерами конечной области
// эта функция используется как внутренняя, исходные данные должны быть уже проверены.
// в качестве аргументов получает поверхности экрана, описанные выше (surface_desc)
// row_first1 пробегает строчки, куда копировать, от начала до конца, с шагом stride
// row_last1 - это и есть конец (посчитали и запомнили)
// row_first1 пробегает строчки, откуда копировать, с шагом stride
for(surf_bit_t *row_first1=to->begin,
*row_last1=to->begin+from->stride*to->width,
*row_first2=from->from->begin;
row_first1<row_last1; row_first1+=to->stride, row_first2+=from->stride)
{
// закомментирован пример кода для копирования,
// можешь поиграться с ним (переделать в закрашивание)
for(unsigned col=0; col<to->width; ++col)
{
// копирование
row_first1[col] = row_first2[col];
// а это могло бы быть закрашивание
// row_first1[col] = 2;
}
// простейший случай - просто копирование памяти. Сэкономил код функцией
// memcpy(row_first2, row_first1, to->width*sizeof(surf_bit_t));
}
}
inline int __constraint(int x, int min, int max)
{
// ограничивает значение x - прибмвает к одному из порогов.
// нужно для пересечения прямоугольников
return x < min ? min : (x < max ? x : max);
}
// функция, которая вычисляет аргументы для __blt
// x x x x x x по заданным исходному прямоугольнику и конечной
// x x 1 1 1 1 y 1 1 1 1 y y точке, куда содержимое этого прямоугольника
// x x 1 0 0 0 -> y 1 0 0 0 y y скопировать.
// x x 1 0 0 0 y 1 0 0 0 y y Надо учесть случаи, когда часть прямоугольника
// x x x x x x будет выходить за пределы исходного или
// конечного экранов. Для этого сделаем следующее:
// (1) пересчитаем координаты прямоугольников экранов в координатах исходного и конечного
// прямоугольника, (2) пересечём их с исходным и конечным прямоугольником. Затем (3)
// пересечём что получилось между собой. Получится прямоугольник (4), который и надо
// копировать. Пересчитаем его в координатах экранов (5), запишем в виде поверхностей (6) и
// отдадим функции __blt
//
// (0,0) (0,0) (0,0)
// +---+ (w,0) +---+ (w,0) +---+ (w,0)
// | | | | | |
// | x|x x x |y y|y y y -> | N| область, которая_
// | x|x x x |y y|y y y | N| будет скопирована
// +--x+x x x +y-y+y y y +--N+
// (0,h) x x x x (0,h) (0,h)
//
void blt(surface_desc* from, /*поверхность-откуда*/
int x, int y, /*координаты, откуда копировать*/
int width, int height, /*размеры окошка*/
surface_desc* to, /*поверхность-куда*/
int to_x, int to_y) /*координаты куда*/
{
// более удобный для пользователя интерфейс
// с проверкой исходных данных
// вычисляем перекрывающийся прямоугольник для копирования.
surface_desc from1, to1;
{
// пересечение прямоугольника {0, 0, width, height} с
// исходным изображением, в координатах копируемого окошка
rect_t rect_src = {
/*2*/__constraint(/*1*/-x, 0, width),
/*2*/__constraint(/*1*/-y, 0, height),
/*2*/__constraint(/*1*/from->width - x, 0, width),
/*2*/__constraint(/*1*/from->height - y, 0, height)},
// пересечение {0, 0, width, height} с
// конечным изображением и сразу с пересечённым исходным rect_src
rect_dest = /*4*/{
/*3*/__constraint(/*2*/__constraint(/*1*/-x_to, 0, width), rect_src.left, rect_src.right),
/*3*/__constraint(/*2*/__constraint(/*1*/-y_to, 0, height), rect_src.top, rect_src.bottom),
/*3*/__constraint(/*2*/__constraint(/*1*/to->width - x_to, 0, width), rect_src.left, rect_src.right),
/*3*/__constraint(/*2*/__constraint(/*1*/to->height - y_to, 0, height), rect_src.top, rect_src.bottom)};
// составляем полётное задание для __blt
from1.begin = /*6*/from->begin + (/*5*/rect_dest.top + y)*from->stride + /*5*/rect_dest.left + x;
from1.stride = /*6*/from->stride; /*сохраняется для подобласти*/
from1.width = /*6*/rect_desc.right - rect_dest.left;
from1.height = /*6*/rect_desc.bottom - rect_dest.top;
to1.begin = /*6*/to->begin + (/*5*/rect_dest.top + to_y)*from->stride + /*5*/rect_dest.left + to_x;
to1.stride = /*6*/to->stride; /*сохраняется для подобласти*/
to1.width = /*6*/rect_desc.right - rect_dest.left;
to1.height = /*6*/rect_desc.bottom - rect_dest.top;
}
__blt(&from1, &to1);
}
// как пользоваться_
// где-то в программе выделена память под экран, сделано описание для этой памяти:
surf_bit_t screen1_bits[/*width*/320 * /*height*/200];
surface_desc screen1 = {/*begin*/ &screen1_bits, /*width*/320, /*height*/200, /*stride=width*/320};
surf_bit_t screen2_bits[/*width*/50 * /*height*/100];
surface_desc screen2 = {/*begin*/ &screen2_bits, /*width*/50, /*height*/100, /*stride=width*/50};
// в том месте, где надо скопировать делаем так:
// копируем прямоугольник 60x60 из точки (100,100) в (10,10) на другом экране
blt(&screen1, 100, 100, 60, 60, &screen2, 10, 10);