public static void ScaleImage(ScaleSize scaleSize, sPixel[] src, sPixel[] trg, int srcWidth, int srcHeight, int xFirst, int yFirst, int xLast, int yLast)
        {
            yFirst = Math.Max(yFirst, 0);
            yLast  = Math.Min(yLast, srcHeight);

            if (yFirst >= yLast || srcWidth <= 0)
            {
                return;
            }

            var trgWidth = srcWidth * scaleSize.size;

            //temporary buffer for "on the fly preprocessing"
            var preProcBuffer = new byte[srcWidth];

            var ker4 = new Kernel_4X4();

            var preProcessCornersColorDist = new ColorDistA();

            //initialize preprocessing buffer for first row:
            //detect upper left and right corner blending
            //this cannot be optimized for adjacent processing
            //stripes; we must not allow for a memory race condition!
            if (yFirst > 0)
            {
                var y = yFirst - 1;

                var sM1 = srcWidth * Math.Max(y - 1, 0);
                var s0  = srcWidth * y;                //center line
                var sP1 = srcWidth * Math.Min(y + 1, srcHeight - 1);
                var sP2 = srcWidth * Math.Min(y + 2, srcHeight - 1);

                for (var x = xFirst; x < xLast; ++x)
                {
                    var xM1 = Math.Max(x - 1, 0);
                    var xP1 = Math.Min(x + 1, srcWidth - 1);
                    var xP2 = Math.Min(x + 2, srcWidth - 1);

                    //read sequentially from memory as far as possible
                    ker4.b = src[sM1 + x];
                    ker4.c = src[sM1 + xP1];

                    ker4.e = src[s0 + xM1];
                    ker4.f = src[s0 + x];
                    ker4.g = src[s0 + xP1];
                    ker4.h = src[s0 + xP2];

                    ker4.i = src[sP1 + xM1];
                    ker4.j = src[sP1 + x];
                    ker4.k = src[sP1 + xP1];
                    ker4.l = src[sP1 + xP2];

                    ker4.n = src[sP2 + x];
                    ker4.o = src[sP2 + xP1];

                    var blendResult = new BlendResult();
                    _PreProcessCorners(ker4, blendResult, preProcessCornersColorDist);                     // writes to blendResult

                    /*
                     * preprocessing blend result:
                     * ---------
                     | F | G | //evalute corner between F, G, J, K
                     | ----|---| //input pixel is at position F
                     | J | K |
                     | ---------
                     */
                    preProcBuffer[x] = BlendInfo.SetTopR(preProcBuffer[x], blendResult.j);

                    if (x + 1 < srcWidth)
                    {
                        preProcBuffer[x + 1] = BlendInfo.SetTopL(preProcBuffer[x + 1], blendResult.k);
                    }
                }
            }

            var eqColorThres = _Square(_CONFIGURATION.equalColorTolerance);

            var scalePixelColorEq   = new ColorEqA(eqColorThres);
            var scalePixelColorDist = new ColorDistA();
            var outputMatrix        = new OutputMatrix(scaleSize.size, trg, trgWidth);

            var ker3 = new Kernel_3X3();

            for (var y = yFirst; y < yLast; ++y)
            {
                //consider MT "striped" access
                var trgi = scaleSize.size * y * trgWidth;

                var sM1 = srcWidth * Math.Max(y - 1, 0);
                var s0  = srcWidth * y;                //center line
                var sP1 = srcWidth * Math.Min(y + 1, srcHeight - 1);
                var sP2 = srcWidth * Math.Min(y + 2, srcHeight - 1);

                byte blendXy1 = 0;

                for (var x = xFirst; x < xLast; ++x, trgi += scaleSize.size)
                {
                    var xM1 = Math.Max(x - 1, 0);
                    var xP1 = Math.Min(x + 1, srcWidth - 1);
                    var xP2 = Math.Min(x + 2, srcWidth - 1);

                    //evaluate the four corners on bottom-right of current pixel
                    //blend_xy for current (x, y) position
                    byte blendXy;
                    {
                        //read sequentially from memory as far as possible
                        ker4.b = src[sM1 + x];
                        ker4.c = src[sM1 + xP1];

                        ker4.e = src[s0 + xM1];
                        ker4.f = src[s0 + x];
                        ker4.g = src[s0 + xP1];
                        ker4.h = src[s0 + xP2];

                        ker4.i = src[sP1 + xM1];
                        ker4.j = src[sP1 + x];
                        ker4.k = src[sP1 + xP1];
                        ker4.l = src[sP1 + xP2];

                        ker4.n = src[sP2 + x];
                        ker4.o = src[sP2 + xP1];

                        var blendResult = new BlendResult();
                        _PreProcessCorners(ker4, blendResult, preProcessCornersColorDist);                         // writes to blendResult

                        /*
                         * preprocessing blend result:
                         * ---------
                         | F | G | //evaluate corner between F, G, J, K
                         | ----|---| //current input pixel is at position F
                         | J | K |
                         | ---------
                         */

                        //all four corners of (x, y) have been determined at
                        //this point due to processing sequence!
                        blendXy = BlendInfo.SetBottomR(preProcBuffer[x], blendResult.f);

                        //set 2nd known corner for (x, y + 1)
                        blendXy1 = BlendInfo.SetTopR(blendXy1, blendResult.j);
                        //store on current buffer position for use on next row
                        preProcBuffer[x] = blendXy1;

                        //set 1st known corner for (x + 1, y + 1) and
                        //buffer for use on next column
                        blendXy1 = BlendInfo.SetTopL(0, blendResult.k);

                        if (x + 1 < srcWidth)
                        {
                            //set 3rd known corner for (x + 1, y)
                            preProcBuffer[x + 1] = BlendInfo.SetBottomL(preProcBuffer[x + 1], blendResult.g);
                        }
                    }

                    //fill block of size scale * scale with the given color
                    //  //place *after* preprocessing step, to not overwrite the
                    //  //results while processing the the last pixel!
                    _FillBlock(trg, trgi, trgWidth, src[s0 + x], scaleSize.size);

                    //blend four corners of current pixel
                    if (blendXy == 0)
                    {
                        continue;
                    }

                    const int a = 0, b = 1, c = 2, d = 3, e = 4, f = 5, g = 6, h = 7, i = 8;

                    //read sequentially from memory as far as possible
                    ker3._[a] = src[sM1 + xM1];
                    ker3._[b] = src[sM1 + x];
                    ker3._[c] = src[sM1 + xP1];

                    ker3._[d] = src[s0 + xM1];
                    ker3._[e] = src[s0 + x];
                    ker3._[f] = src[s0 + xP1];

                    ker3._[g] = src[sP1 + xM1];
                    ker3._[h] = src[sP1 + x];
                    ker3._[i] = src[sP1 + xP1];

                    _ScalePixel(scaleSize.scaler, RotationDegree.Rot0, ker3, trg, trgi, trgWidth, blendXy, scalePixelColorEq, scalePixelColorDist, outputMatrix);
                    _ScalePixel(scaleSize.scaler, RotationDegree.Rot90, ker3, trg, trgi, trgWidth, blendXy, scalePixelColorEq, scalePixelColorDist, outputMatrix);
                    _ScalePixel(scaleSize.scaler, RotationDegree.Rot180, ker3, trg, trgi, trgWidth, blendXy, scalePixelColorEq, scalePixelColorDist, outputMatrix);
                    _ScalePixel(scaleSize.scaler, RotationDegree.Rot270, ker3, trg, trgi, trgWidth, blendXy, scalePixelColorEq, scalePixelColorDist, outputMatrix);
                }
            }
        }
Esempio n. 2
0
    public static void ScaleImage(ScaleSize scaleSize, sPixel[] src, sPixel[] trg, int srcWidth, int srcHeight, int xFirst, int yFirst, int xLast, int yLast) {
      yFirst = Math.Max(yFirst, 0);
      yLast = Math.Min(yLast, srcHeight);

      if (yFirst >= yLast || srcWidth <= 0)
        return;

      var trgWidth = srcWidth * scaleSize.size;

      //temporary buffer for "on the fly preprocessing"
      var preProcBuffer = new byte[srcWidth];

      var ker4 = new Kernel_4X4();

      var preProcessCornersColorDist = new ColorDistA();

      //initialize preprocessing buffer for first row:
      //detect upper left and right corner blending
      //this cannot be optimized for adjacent processing
      //stripes; we must not allow for a memory race condition!
      if (yFirst > 0) {
        var y = yFirst - 1;

        var sM1 = srcWidth * Math.Max(y - 1, 0);
        var s0 = srcWidth * y; //center line
        var sP1 = srcWidth * Math.Min(y + 1, srcHeight - 1);
        var sP2 = srcWidth * Math.Min(y + 2, srcHeight - 1);

        for (var x = xFirst; x < xLast; ++x) {
          var xM1 = Math.Max(x - 1, 0);
          var xP1 = Math.Min(x + 1, srcWidth - 1);
          var xP2 = Math.Min(x + 2, srcWidth - 1);

          //read sequentially from memory as far as possible
          ker4.b = src[sM1 + x];
          ker4.c = src[sM1 + xP1];

          ker4.e = src[s0 + xM1];
          ker4.f = src[s0 + x];
          ker4.g = src[s0 + xP1];
          ker4.h = src[s0 + xP2];

          ker4.i = src[sP1 + xM1];
          ker4.j = src[sP1 + x];
          ker4.k = src[sP1 + xP1];
          ker4.l = src[sP1 + xP2];

          ker4.n = src[sP2 + x];
          ker4.o = src[sP2 + xP1];

          var blendResult = new BlendResult();
          _PreProcessCorners(ker4, blendResult, preProcessCornersColorDist); // writes to blendResult
          /*
     preprocessing blend result:
     ---------
     | F | G | //evalute corner between F, G, J, K
     ----|---| //input pixel is at position F
     | J | K |
     ---------
     */
          preProcBuffer[x] = BlendInfo.SetTopR(preProcBuffer[x], blendResult.j);

          if (x + 1 < srcWidth)
            preProcBuffer[x + 1] = BlendInfo.SetTopL(preProcBuffer[x + 1], blendResult.k);
        }
      }

      var eqColorThres = _Square(_CONFIGURATION.equalColorTolerance);

      var scalePixelColorEq = new ColorEqA(eqColorThres);
      var scalePixelColorDist = new ColorDistA();
      var outputMatrix = new OutputMatrix(scaleSize.size, trg, trgWidth);

      var ker3 = new Kernel_3X3();

      for (var y = yFirst; y < yLast; ++y) {
        //consider MT "striped" access
        var trgi = scaleSize.size * y * trgWidth;

        var sM1 = srcWidth * Math.Max(y - 1, 0);
        var s0 = srcWidth * y; //center line
        var sP1 = srcWidth * Math.Min(y + 1, srcHeight - 1);
        var sP2 = srcWidth * Math.Min(y + 2, srcHeight - 1);

        byte blendXy1 = 0;

        for (var x = xFirst; x < xLast; ++x, trgi += scaleSize.size) {
          var xM1 = Math.Max(x - 1, 0);
          var xP1 = Math.Min(x + 1, srcWidth - 1);
          var xP2 = Math.Min(x + 2, srcWidth - 1);

          //evaluate the four corners on bottom-right of current pixel
          //blend_xy for current (x, y) position
          byte blendXy;
          {
            //read sequentially from memory as far as possible
            ker4.b = src[sM1 + x];
            ker4.c = src[sM1 + xP1];

            ker4.e = src[s0 + xM1];
            ker4.f = src[s0 + x];
            ker4.g = src[s0 + xP1];
            ker4.h = src[s0 + xP2];

            ker4.i = src[sP1 + xM1];
            ker4.j = src[sP1 + x];
            ker4.k = src[sP1 + xP1];
            ker4.l = src[sP1 + xP2];

            ker4.n = src[sP2 + x];
            ker4.o = src[sP2 + xP1];

            var blendResult = new BlendResult();
            _PreProcessCorners(ker4, blendResult, preProcessCornersColorDist); // writes to blendResult

            /*
      preprocessing blend result:
      ---------
      | F | G | //evaluate corner between F, G, J, K
      ----|---| //current input pixel is at position F
      | J | K |
      ---------
      */

            //all four corners of (x, y) have been determined at
            //this point due to processing sequence!
            blendXy = BlendInfo.SetBottomR(preProcBuffer[x], blendResult.f);

            //set 2nd known corner for (x, y + 1)
            blendXy1 = BlendInfo.SetTopR(blendXy1, blendResult.j);
            //store on current buffer position for use on next row
            preProcBuffer[x] = blendXy1;

            //set 1st known corner for (x + 1, y + 1) and
            //buffer for use on next column
            blendXy1 = BlendInfo.SetTopL(0, blendResult.k);

            if (x + 1 < srcWidth)
              //set 3rd known corner for (x + 1, y)
              preProcBuffer[x + 1] = BlendInfo.SetBottomL(preProcBuffer[x + 1], blendResult.g);
          }

          //fill block of size scale * scale with the given color
          //  //place *after* preprocessing step, to not overwrite the
          //  //results while processing the the last pixel!
          _FillBlock(trg, trgi, trgWidth, src[s0 + x], scaleSize.size);

          //blend four corners of current pixel
          if (blendXy == 0)
            continue;

          const int a = 0, b = 1, c = 2, d = 3, e = 4, f = 5, g = 6, h = 7, i = 8;

          //read sequentially from memory as far as possible
          ker3._[a] = src[sM1 + xM1];
          ker3._[b] = src[sM1 + x];
          ker3._[c] = src[sM1 + xP1];

          ker3._[d] = src[s0 + xM1];
          ker3._[e] = src[s0 + x];
          ker3._[f] = src[s0 + xP1];

          ker3._[g] = src[sP1 + xM1];
          ker3._[h] = src[sP1 + x];
          ker3._[i] = src[sP1 + xP1];

          _ScalePixel(scaleSize.scaler, RotationDegree.Rot0, ker3, trg, trgi, trgWidth, blendXy, scalePixelColorEq, scalePixelColorDist, outputMatrix);
          _ScalePixel(scaleSize.scaler, RotationDegree.Rot90, ker3, trg, trgi, trgWidth, blendXy, scalePixelColorEq, scalePixelColorDist, outputMatrix);
          _ScalePixel(scaleSize.scaler, RotationDegree.Rot180, ker3, trg, trgi, trgWidth, blendXy, scalePixelColorEq, scalePixelColorDist, outputMatrix);
          _ScalePixel(scaleSize.scaler, RotationDegree.Rot270, ker3, trg, trgi, trgWidth, blendXy, scalePixelColorEq, scalePixelColorDist, outputMatrix);
        }
      }
    }