The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
#define IMAGER_NO_CONTEXT
#include "imager.h"

static void flip_h(i_img *im);
static void flip_v(i_img *im);
static void flip_hv(i_img *im);

#define XAXIS 0
#define YAXIS 1
#define XYAXIS 2

/*
=item i_flipxy(im, axis)

Flips the image inplace around the axis specified.
Returns 0 if parameters are invalid.

   im   - Image pointer
   axis - 0 = x, 1 = y, 2 = both

=cut
*/

undef_int
i_flipxy(i_img *im, int direction) {
  dIMCTXim(im);
  i_clear_error();

  im_log((aIMCTX, 1, "i_flipxy(im %p, direction %d)\n", im, direction ));

  if (!im)
    return 0;

  switch (direction) {
  case XAXIS: /* Horizontal flip */
    flip_h(im);
    break;

  case YAXIS: /* Vertical flip */
    flip_v(im);
    break;

  case XYAXIS: /* Horizontal and Vertical flip */
    flip_hv(im);
    break;

  default:
    im_log((aIMCTX, 1, "i_flipxy: direction is invalid\n" ));
    im_push_errorf(aIMCTX, 0, "direction %d invalid", direction);
    return 0;
  }
  return 1;
}

static void
flip_row_pal(i_palidx *row, i_img_dim width) {
  i_palidx tmp;
  i_palidx *leftp = row;
  i_palidx *rightp = row + width - 1;
  
  while (leftp < rightp) {
    tmp = *leftp;
    *leftp = *rightp;
    *rightp = tmp;
    ++leftp;
    --rightp;
  }
}

#code

static void
IM_SUFFIX(flip_row)(IM_COLOR *row, i_img_dim width) {
  IM_COLOR tmp;
  IM_COLOR *leftp = row;
  IM_COLOR *rightp = row + width - 1;
  
  while (leftp < rightp) {
    tmp = *leftp;
    *leftp = *rightp;
    *rightp = tmp;
    ++leftp;
    --rightp;
  }
}

#/code

static void
flip_h(i_img *im) {
  i_img_dim y;
  if (im->type == i_palette_type) {
    i_palidx *line = mymalloc(im->xsize * sizeof(i_palidx));
    for (y = 0; y < im->ysize; ++y) {
      i_gpal(im, 0, im->xsize, y, line);
      flip_row_pal(line, im->xsize);
      i_ppal(im, 0, im->xsize, y, line);
    }
    myfree(line);
  }
  else {
#code im->bits == i_8_bits
    IM_COLOR *line = mymalloc(im->xsize * sizeof(IM_COLOR));
    for (y = 0; y < im->ysize; ++y) {
      IM_GLIN(im, 0, im->xsize, y, line);
      IM_SUFFIX(flip_row)(line, im->xsize);
      IM_PLIN(im, 0, im->xsize, y, line);
    }
    myfree(line);
#/code
  }
}

static void
flip_v(i_img *im) {
  i_img_dim topy = 0;
  i_img_dim boty = im->ysize - 1;
  if (im->type == i_palette_type) {
    i_palidx *top_line = mymalloc(im->xsize * sizeof(i_palidx));
    i_palidx *bot_line = mymalloc(im->xsize * sizeof(i_palidx));
    while (topy < boty) {
      i_gpal(im, 0, im->xsize, topy, top_line);
      i_gpal(im, 0, im->xsize, boty, bot_line);
      i_ppal(im, 0, im->xsize, topy, bot_line);
      i_ppal(im, 0, im->xsize, boty, top_line);
      ++topy;
      --boty;
    }
    myfree(bot_line);
    myfree(top_line);
  }
  else {
#code im->bits == i_8_bits
    IM_COLOR *top_line = mymalloc(im->xsize * sizeof(IM_COLOR));
    IM_COLOR *bot_line = mymalloc(im->xsize * sizeof(IM_COLOR));
    while (topy < boty) {
      IM_GLIN(im, 0, im->xsize, topy, top_line);
      IM_GLIN(im, 0, im->xsize, boty, bot_line);
      IM_PLIN(im, 0, im->xsize, topy, bot_line);
      IM_PLIN(im, 0, im->xsize, boty, top_line);
      ++topy;
      --boty;
    }
    myfree(top_line);
    myfree(bot_line);
#/code 
  }
}

static void
flip_hv(i_img *im) {
  i_img_dim topy = 0;
  i_img_dim boty = im->ysize - 1;
  if (im->type == i_palette_type) {
    i_palidx *top_line = mymalloc(im->xsize * sizeof(i_palidx));
    i_palidx *bot_line = mymalloc(im->xsize * sizeof(i_palidx));
    while (topy < boty) {
      i_gpal(im, 0, im->xsize, topy, top_line);
      i_gpal(im, 0, im->xsize, boty, bot_line);
      flip_row_pal(top_line, im->xsize);
      flip_row_pal(bot_line, im->xsize);
      i_ppal(im, 0, im->xsize, topy, bot_line);
      i_ppal(im, 0, im->xsize, boty, top_line);
      ++topy;
      --boty;
    }
    myfree(bot_line);
    myfree(top_line);
  }
  else {
#code im->bits == i_8_bits
    IM_COLOR *top_line = mymalloc(im->xsize * sizeof(IM_COLOR));
    IM_COLOR *bot_line = mymalloc(im->xsize * sizeof(IM_COLOR));
    while (topy < boty) {
      IM_GLIN(im, 0, im->xsize, topy, top_line);
      IM_GLIN(im, 0, im->xsize, boty, bot_line);
      IM_SUFFIX(flip_row)(top_line, im->xsize);
      IM_SUFFIX(flip_row)(bot_line, im->xsize);
      IM_PLIN(im, 0, im->xsize, topy, bot_line);
      IM_PLIN(im, 0, im->xsize, boty, top_line);
      ++topy;
      --boty;
    }
    if (topy == boty) {
      IM_GLIN(im, 0, im->xsize, topy, top_line);
      IM_SUFFIX(flip_row)(top_line, im->xsize);
      IM_PLIN(im, 0, im->xsize, topy, top_line);
    }
    myfree(top_line);
    myfree(bot_line);
#/code 
  }
}