HT1632C homemade LED matrix software

I'm making something almost identical to this using the HT1632C along with this library. I messed up the construction of my matrix (mixed up the anodes and cathodes), so my rows are now columns and vice versa, resulting in everything being rotated by 90° (but accurate).

My code is identical to the examples in the library and I'm at wits end trying to find a programmatic solution. I really don't want to take the matrix apart. Here's what I've tried (from other suggestions):

  • Reverse the x and y in HT1632C.h on the following line:
#define GET_ADDR_FROM_X_Y(_x,_y) ((_x)*2+(_y)/4)

This did not result in anything productive and generally messed up everything.

  • Reverse the x and y in HT1632C.cpp in the drawText function
    This resulted in the text scrolling in the right direction but it was still had a rotated orientation.
  • Reverse the x and y in the drawImage function
    Depending on where I changed things, this either has no effect or the same effect as the first point.

I feel pretty strongly that the fix is in the drawImage function but I'm just not seeing it. Any suggestions?

EDIT: The drawImage function is below

void HT1632Class::drawImage(const char * img, char width, char height, char x, char y, int offset){
  char length = width*height/4;
  char mask;
  
  // Sanity checks
  if(y + height < 0 || x + width < 0 || y > COM_SIZE || x > OUT_SIZE)
    return;
  // After looking at the rest of this function, you may need one.
  
  // Copying Engine.
  // You are not expected to understand this.
  for(char i=0; i<width; ++i) {
    char carryover_y = 0; // Simply a copy of the last 4-bit word of img.
    char carryover_num = (y - (y & ~ 3)); // Number of digits carried over
    bool carryover_valid = false; // If true, there is data to be carried over.
    
    char loc_x = i + x;
    if(loc_x < 0 || loc_x >= OUT_SIZE) // Skip this column if it is out of range.
      continue;
    for(char j=0; j < (carryover_valid ? (height+4):height) ; j+=4) {
      char loc_y = j + y;
      if(loc_y <= -4 || loc_y >= COM_SIZE) // Skip this row if it is out of range.
        continue;
      // Direct copying possible when render is on boundaries.
      // The bit manipulation here is designed to copy from img only the relevant sections.
      
      // This mask is only not used when emptying the cache (for copying to non-4-bit aligned spaces)
     
      //if(j<height)
      // mask = (height-loc_y >= 4)?0b00001111:(0b00001111 >> (4-(height-j))) & 0b00001111; // Mask bottom
        
      if(loc_y % 4 == 0) {
          mask = (height-loc_y >= 4)?0b00001111:(0b00001111 >> (4-(height-j))) & 0b00001111;
          mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] = (mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] & (~mask) & 0b00001111) | (img[(int)ceil((float)height/4.0f)*i + j/4 + offset] & mask) | MASK_NEEDS_REWRITING;
      } else {
        // If carryover_valid is NOT true, then this is the first set to be copied.
        // If loc_y > 0, preserve the contents of the pixels above, copy to mem, and then copy remaining
        // data to the carry over buffer. If y loc_y < 0, just copy data to carry over buffer.
        // It is expected that this section is only reached when j == 0.
        // COPY START
        if(!carryover_valid) {
          if(loc_y > 0) {
            mask = (height-loc_y >= 4)?0b00001111:(0b00001111 >> (4-(height-j))) & 0b00001111; // Mask bottom
            mask = (0b00001111 << carryover_num) & mask; // Mask top
            mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] = (mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] & (~mask) & 0b00001111) | ((img[(int)ceil((float)height/4.0f)*i + j/4 + offset] << carryover_num) & mask) | MASK_NEEDS_REWRITING;
          }
          carryover_valid = true;
        } else {
          // COPY END
          if(j >= height) {
            // Its writing one line past the end.
            // Use this line to get rid of the final carry-over.
            mask = (0b00001111 >> (4 - carryover_num)) & 0b00001111; // Mask bottom
            mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] = (mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] & (~mask) & 0b00001111) | (carryover_y >> (4 - carryover_num) & mask) | MASK_NEEDS_REWRITING;
          // COPY MIDDLE
          } else {
            // There is data in the carry-over buffer. Copy that data and the values from the current cell into mem.
            // The inclusion of a carryover_num term is to account for the presence of the carryover data when calculating the bottom clipping.
            mask = (height-loc_y >= 4)?0b00001111:(0b00001111 >> (4-(height+carryover_num-j))) & 0b00001111; // Mask bottom
            mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] = (mem[_tgtBuffer][GET_ADDR_FROM_X_Y(loc_x,loc_y)] & (~mask) & 0b00001111) | ((img[(int)ceil((float)height/4.0f)*i + j/4 + offset] << carryover_num) & mask) | (carryover_y >> (4 - carryover_num) & mask) | MASK_NEEDS_REWRITING;
          }
        }
        carryover_y = img[(int)ceil((float)height/4.0f)*i + j/4 + offset];
      }
    }
  }
}