//+----------------------------------------------------------------------------+ //| Description: Magic Set Editor - Program to make Magic (tm) cards | //| Copyright: (C) 2001 - 2007 Twan van Laarhoven | //| License: GNU General Public License 2 or later (see file COPYING) | //+----------------------------------------------------------------------------+ // ----------------------------------------------------------------------------- : Includes #include #include // ----------------------------------------------------------------------------- : Resample passes // bitshift for fixed point numbers // higher is less error // we will get errors if 2^shift * imagesize becomes too large const int shift = 32-10-8; // => max size = 1024, max alpha = 255 // Resample an image only in a single direction, either horizontally or vertically /* Terms are based on x resampling (keeping the same number of lines): * offset = number of elements to skip at the start * length = length of a line * delta = number of elements between pixels in a lines * lines = number of lines * line_delta = number of elements between the the first pixel of two lines * 1 element = 3 bytes in data, 1 byte in alpha */ void resample_pass(const Image& img_in, Image& img_out, int offset_in, int offset_out, int length_in, int delta_in, int length_out, int delta_out, int lines, int line_delta_in, int line_delta_out) { bool alpha = img_in.HasAlpha(); if (alpha && !img_out.HasAlpha()) img_out.InitAlpha(); int out_fact = (length_out << shift) / length_in; // how much to output for 256 input = 1 pixel int out_rest = (length_out << shift) % length_in; // for each line for (int l = 0 ; l < lines ; ++l) { Byte* in = img_in .GetData() + 3 * (offset_in + l * line_delta_in); Byte* out = img_out.GetData() + 3 * (offset_out + l * line_delta_out); UInt in_rem = out_fact + out_rest; // remaining to input from the current input pixel if (alpha) { Byte* in_a = img_in .GetAlpha() + (offset_in + l * line_delta_in); Byte* out_a = img_out.GetAlpha() + (offset_out + l * line_delta_out); for (int x = 0 ; x < length_out ; ++x) { UInt out_rem = 1 << shift; UInt totR = 0, totG = 0, totB = 0, totA = 0; while (out_rem >= in_rem) { // eat a whole input pixel totR += in[0] * in_rem * in_a[0]; // multiply by alpha totG += in[1] * in_rem * in_a[0]; totB += in[2] * in_rem * in_a[0]; totA += in_a[0] * in_rem; out_rem -= in_rem; in_rem = out_fact; in += 3*delta_in; in_a += delta_in; } if (out_rem > 0) { // eat a partial input pixel totR += in[0] * out_rem * in_a[0]; totG += in[1] * out_rem * in_a[0]; totB += in[2] * out_rem * in_a[0]; totA += in_a[0] * out_rem; in_rem -= out_rem; } // store if (totA) { out[0] = totR / totA; out[1] = totG / totA; out[2] = totB / totA; out_a[0] = totA >> shift; } else { out[0] = out[1] = out[2] = out_a[0] = 0; // div by 0 is bad } out += 3*delta_out; out_a += delta_out; } } else { // no alpha for (int x = 0 ; x < length_out ; ++x) { UInt out_rem = 1 << shift; UInt totR = 0, totG = 0, totB = 0; while (out_rem >= in_rem) { // eat a whole input pixel totR += in[0] * in_rem; totG += in[1] * in_rem; totB += in[2] * in_rem; out_rem -= in_rem; in_rem = out_fact; in += 3*delta_in; } if (out_rem > 0) { // eat a partial input pixel totR += in[0] * out_rem; totG += in[1] * out_rem; totB += in[2] * out_rem; in_rem -= out_rem; } // store out[0] = totR >> shift; out[1] = totG >> shift; out[2] = totB >> shift; out += 3*delta_out; } } } } // ----------------------------------------------------------------------------- : Resample /* The algorithm first resizes in horizontally, then vertically, * the two passes are essentially the same: * - for each row: * - each input pixel becomes a fixed amount of output (in 1< 0); Byte *in = img_in.GetData(), *out = img_out.GetData(); for (int y = 0 ; y < height ; ++y) { for (int x = 0 ; x < width ; ++x) { for (int c = 0 ; c < 3 ; ++c) { // for each component // Filter using a kernel of the form /* -1 -1 * -1 c c -1 * -1 c c -1 * -1 -1 * But when we are near the edge replicate the edge pixel */ int tot = center_weight * (in[0] + in[3] + in[line] + in[line+3]) - // center border_weight * ( (x == 0 ? in[0] + in[line] : in[-3] + in[line-3]) + // left (x+1 == width ? in[3] + in[line+3] : in[6] + in[line+6]) + // right (y == 0 ? in[0] + in[3] : in[-line] + in[3-line]) + // top (y+1 == height ? in[line] + in[line+3] : in[line*2] + in[line*2+3]) );// bottom // And then avarage the result into a single pixel (downsample by factor 2) out[0] = col( tot / (4 * center_weight - 8 * border_weight) ); // next pixel ++in; ++out; } // skip a pixel in += 3; } // skip a line in += line; } }