// оптимизированная вставка с учётом границ:
template <blend_pf f>
void Image::make_print(int posx, int posy, Image& dst) const {
  if ( !check() || !dst.check()) return;
  if (posx >= dst.getX()) return;
  if (posy >= dst.getY()) return;
  auto ey = posy + getY();
  auto ex = posx + getX();
  if (ex <= 0) return;
  if (ey <= 0) return;
  if (ey > dst.getY()) ey = dst.getY();
  if (ex > dst.getX()) ex = dst.getX();
  cauto old_posy = posy;
  cauto old_posx = posx;
  if (posx < 0) posx = 0;
  if (posy < 0) posy = 0;
  for (int y = posy; y < ey; ++y)
  for (int x = posx; x < ex; ++x)
    f(fast_get(x - old_posx, y - old_posy), *dst.fast_get_ptr(x, y));
}
template <blend_pf f>
void Image::make_draw_rect_filled(int sx, int sy, int mx, int my, Color col) {
  if ( !check()) return;
  if (mx < 1 || my < 1) return;
  cauto ex = sx + mx;
  cauto ey = sy + my;
  for (int y = sy; y < ey; ++y)
  for (int x = sx; x < ex; ++x) {
    auto* src = this->get_ptr(x, y);
    if (src)
      f(col, *src);
  }
}
template <blend_pf f>
void Image::make_fast_print(Image& dst) const {
  for (int i = 0; i < size(); ++i)
    f(fast_get(i), *dst.fast_get_ptr(i));
}
template<blend_pf f>
void Image::make_print_blink_dot2(Image& dst, CN(Vec) pos, int timer) const {
  constexpr int dots2x2[2][2] = {
    {0, 1},
    {1, 0} };
  //! оптимизация по размеру вставки
  if ( !check() || !dst.check()) return;
  int posx = pos.x;
  int posy = pos.y;
  if (posx >= dst.getX()) return;
  if (posy >= dst.getY()) return;
  auto ey = posy + this->getY();
  auto ex = posx + this->getX();
  if (ex <= 0) return;
  if (ey <= 0) return;
  if (ey > dst.getY()) ey = dst.getY();
  if (ex > dst.getX()) ex = dst.getX();
  cauto old_posy = posy;
  cauto old_posx = posx;
  if (posx < 0) posx = 0;
  if (posy < 0) posy = 0;
  for (int y = posy; y < ey; ++y)
  for (int x = posx; x < ex; ++x) {
    // оптимизация без использования ветвления
    CN(Color) SRC = fast_get(x - old_posx, y - old_posy);
    Color &DST = *dst.fast_get_ptr(x, y);
    Color SRC_DST[2] = {SRC, DST};
    const int mode = dots2x2[x & 1][y & 1] ^ (timer & 1);
    SRC_DST[0] = SRC_DST[mode];
    f(SRC_DST[mode], DST);
  }
}