Ignore:
Timestamp:
Dec 22, 2016, 8:49:19 PM (8 years ago)
Author:
chronos
Message:
  • Modified: Updated BGRABitmap package.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest/Packages/bgrabitmap/blurnormal.inc

    r472 r494  
     1type
     2  PWeightedPixel = ^TWeightedPixel;
     3  TWeightedPixel = packed record
     4    Coord: TPoint;
     5    Weight: NativeInt;
     6    PtrOfs: NativeInt;
     7  end;
     8
    19var
    210  maskWidth,maskHeight: integer;
    3   blurOfs:      TPoint;
    4   PixelWeight:  array of integer;
    5   PixelOfs:     array of TPoint;
     11  blurOfs: TPoint;
     12  ppixel: PWeightedPixel;
     13  Pixel: array of TWeightedPixel;
    614  PixelArrayLineStart: array of integer;
    7   DiffPixelWeight:  array of integer;
    8   DiffPixelOfs:     array of TPoint;
     15  DiffPixel: array of TWeightedPixel;
    916  DiffPixelArrayLineStart: array of integer;
    1017
    11   procedure LoadMask;
    12   var x,y,n: integer;
    13       tempWeight: integer;
    14       diffMask: array of array of integer;
     18  bmpWidth,bmpHeight,lineDelta: NativeInt;
     19
     20  procedure LoadMask(out ABlurOfs: TPoint);
     21  var x,y,n,i: NativeInt;
     22      tempWeight: NativeInt;
     23      diffMask: array of packed array of NativeInt;
     24      p: PBGRAPixel;
    1525  begin
    16     blurOfs := point(blurMask.Width shr 1, blurMask.Height shr 1);
     26    ABlurOfs := point(blurMask.Width shr 1, blurMask.Height shr 1);
    1727
    1828    //count number of non empty pixels
     
    2030    maskHeight := blurMask.Height;
    2131    n := 0;
    22     for y := 0 to maskHeight - 1 do
    23       for x := 0 to maskWidth - 1 do
    24         if blurMask.GetPixel(x, y).red <> 0 then Inc(n);
     32    p := blurMask.Data;
     33    for i := blurMask.NbPixels-1 downto 0 do
     34    begin
     35      if p^.red <> 0 then inc(n);
     36      inc(p);
     37    end;
    2538
    2639    //initialize arrays
    2740    setlength(diffMask, maskHeight, maskWidth+1);
    2841    for y := 0 to maskHeight - 1 do
    29       for x := 0 to maskWidth do
    30         diffMask[y,x] := 0;
    31 
    32     setlength(PixelWeight, n);
    33     setlength(PixelOfs, n);
     42      fillchar(diffMask[y,0], (maskWidth+1)*sizeof(NativeInt), 0);
     43
     44    setlength(Pixel, n);
    3445    setlength(PixelArrayLineStart, maskHeight+1);  //stores the first pixel of each line
    3546    n := 0;
     
    3849    begin
    3950      PixelArrayLineStart[y] := n;
     51      p := blurMask.ScanLine[y];
    4052      for x := 0 to maskWidth - 1 do
    4153      begin
    42         tempWeight := blurMask.GetPixel(x, y).red;
     54        tempWeight := p^.red;
     55        inc(p);
    4356        diffMask[y,x] -= tempWeight;
    4457        diffMask[y,x+1] += tempWeight;
     
    4659        if tempWeight <> 0 then
    4760        begin
    48           PixelWeight[n] := tempWeight;
    49           PixelOfs[n] := Point(x,y);
     61          Pixel[n].Weight := tempWeight;
     62          Pixel[n].Coord := Point(x,y);
     63          Pixel[n].PtrOfs := (y-ABlurOfs.Y)*lineDelta + (x-ABlurOfs.X)*sizeof(TBGRAPixel);
    5064          Inc(n);
    5165        end;
     
    6175
    6276    //initialize arrays
    63     setlength(DiffPixelWeight, n);
    64     setlength(DiffPixelOfs, n);
     77    setlength(DiffPixel, n);
    6578    setlength(DiffPixelArrayLineStart, maskHeight+1);  //stores the first pixel of each diff line
    6679    n := 0;
     
    7487        if tempWeight <> 0 then
    7588        begin
    76           DiffPixelWeight[n] := tempWeight;
    77           DiffPixelOfs[n] := Point(x-1,y);
     89          DiffPixel[n].Weight := tempWeight;
     90          DiffPixel[n].Coord := Point(x-1,y);
     91          DiffPixel[n].PtrOfs := (y-ABlurOfs.Y)*lineDelta + (x-ABlurOfs.X-1)*sizeof(TBGRAPixel);
    7892          Inc(n);
    7993        end;
     
    8397  end;
    8498
    85 var
    86   curScans: array of PBGRAPixel;
    87   bounds: TRect;
    88 
    89   {procedure ShowCurScans;
    90   var str: string;
    91     i: Integer;
    92   begin
    93     str := '';
    94     for i := 0 to high(curScans) do
    95     begin
    96       if i <> 0 then str += ', ';
    97       if curScans[i]=nil then str += 'nil' else
    98         str += 'bmp['+inttostr(curScans[i]-bmp.Data)+']';
    99     end;
    100     ShowMessage(str);
    101   end;}
    102 
    103   function PrepareScan: boolean;
    104   var
    105     bmpY: integer;
    106     y   : Integer;
     99  function PrepareScan(AWantedBounds: TRect; out AClippedBounds: TRect): boolean;
    107100  begin
    108101    //evaluate required bounds taking blur radius into acount
    109     bounds := bmp.GetImageBounds;
    110     if IsRectEmpty(bounds) then
     102    AClippedBounds := bmp.GetImageBounds;
     103    if IsRectEmpty(AClippedBounds) then
    111104    begin
    112105      result := false;
    113106      exit;
    114107    end;
    115     bounds.Left   := max(0, bounds.Left - blurOfs.X);
    116     bounds.Top    := max(0, bounds.Top - blurOfs.Y);
    117     bounds.Right  := min(bmp.Width, bounds.Right + maskWidth - 1 - blurOfs.X);
    118     bounds.Bottom := min(bmp.Height, bounds.Bottom + maskHeight - 1 - blurOfs.Y);
    119     if not IntersectRect(bounds, bounds, ABounds) then
     108    AClippedBounds.Left   := max(0, AClippedBounds.Left - blurOfs.X);
     109    AClippedBounds.Top    := max(0, AClippedBounds.Top - blurOfs.Y);
     110    AClippedBounds.Right  := min(bmpWidth, AClippedBounds.Right + maskWidth - 1 - blurOfs.X);
     111    AClippedBounds.Bottom := min(bmpHeight, AClippedBounds.Bottom + maskHeight - 1 - blurOfs.Y);
     112    if not IntersectRect(AClippedBounds, AClippedBounds, AWantedBounds) then
    120113    begin
    121114      result := false;
     
    123116    end;
    124117
    125     //init scanlines
    126     setlength(curScans, maskHeight);
    127     for y := 0 to maskHeight-1 do
    128     begin
    129       bmpY := y+bounds.Top-blurOfs.Y;
    130       if (bmpY < 0) or (bmpY >= bmp.Height) then
    131         curScans[y] := nil else
    132           curScans[y] := bmp.ScanLine[bmpY];
    133     end;
    134     //ShowCurScans;
    135118    result := true;
    136119  end;
    137120
    138   procedure ShiftScan(NewY: integer); inline;
    139   var y: integer;
    140   begin
    141     for y := 0 to maskHeight-2 do
    142      curScans[y] := curScans[y+1];
    143 
    144     //get next scanline
    145     if newY >= bmp.Height then
    146       curScans[maskHeight-1] := nil
    147     else
    148       curScans[maskHeight-1] := bmp.ScanLine[newY];
    149     //ShowCurScans;
    150   end;
    151 
    152121var
    153   yb, xb: integer;
    154   mindy, maxdy, n: integer;
    155   bmpWidth,bmpX: integer;
    156   pixMaskAlpha, maskAlpha: integer;
     122  bounds: TRect;
     123  yb, xb: NativeInt;
     124  mindy, maxdy, n, nStart, nCount, nDiffStart, nDiffCount: NativeInt;
     125  bmpX,bmpXBase,bmpYBase: NativeInt;
     126  pixMaskAlpha, maskAlpha: NativeInt;
    157127  tempPixel: TBGRAPixel;
    158128  pdest : PBGRAPixel;
    159   pt: TPoint;
     129  psrc : PByte;
    160130
    161131begin
    162   LoadMask;
    163 
    164   if (ADestination.Width <> bmp.Width) or (ADestination.Height <> bmp.Height) then
     132  bmpWidth := bmp.Width;
     133  bmpHeight:= bmp.Height;
     134  if bmp.LineOrder = riloTopToBottom then
     135    lineDelta := bmpWidth*sizeof(TBGRAPixel) else
     136    lineDelta := -bmpWidth*sizeof(TBGRAPixel);
     137
     138  if (ADestination.Width <> bmpWidth) or (ADestination.Height <> bmpHeight) then
    165139    raise exception.Create('Dimension mismatch');
    166140
    167   if not PrepareScan then exit; //nothing to do
    168 
    169   bmpWidth := bmp.Width;
     141  LoadMask(blurOfs);
     142  if not PrepareScan(ABounds, bounds) then exit; //nothing to do
     143
     144  bmpYBase := bounds.Top - blurOfs.Y;
     145
    170146  //loop through destination
    171147  for yb := bounds.Top to bounds.Bottom - 1 do
    172148  begin
    173149    if (ACheckShouldStop <> nil) and ACheckShouldStop(yb) then break;
     150    psrc := PByte(bmp.ScanLine[yb]+bounds.Left);
    174151    pdest := ADestination.ScanLine[yb] + bounds.Left;
    175152    //compute vertical range
    176153    mindy := max(-blurOfs.Y, -yb);
    177     maxdy := min(blurMask.Height - 1 - blurOfs.Y, bmp.Height - 1 - yb);
     154    maxdy := min(blurMask.Height - 1 - blurOfs.Y, bmpHeight - 1 - yb);
    178155
    179156    sumR   := 0;
     
    186163    {$endif}
    187164
     165    bmpXBase := bounds.Left-blurOfs.X;
     166    nStart := PixelArrayLineStart[mindy+blurOfs.Y];
     167    nCount  := PixelArrayLineStart[maxdy+blurOfs.Y+1]-nStart;
     168    ppixel:= @Pixel[nStart];
    188169    //go through pixel list of the current vertical range
    189     for n := PixelArrayLineStart[mindy+blurOfs.Y] to PixelArrayLineStart[maxdy+blurOfs.Y+1]-1 do
    190     begin
    191       pt := PixelOfs[n];
    192       bmpX := bounds.Left-blurOfs.X+pt.x;
     170    for n := nCount-1 downto 0 do
     171    begin
     172      bmpX := bmpXBase+ppixel^.Coord.x;
    193173      //check horizontal range
    194174      if (bmpX >= 0) and (bmpX < bmpWidth) then
    195175      begin
    196         tempPixel := (curScans[pt.y]+bmpX)^;
    197         maskAlpha := PixelWeight[n];
     176        tempPixel := PBGRAPixel(psrc + ppixel^.PtrOfs)^;
     177        maskAlpha := ppixel^.Weight;
    198178        pixMaskAlpha := maskAlpha * tempPixel.alpha;
    199179        sumA    += pixMaskAlpha;
     
    209189        {$hints on}
    210190      end;
    211     end;
    212 
    213     for xb := bounds.Left to Bounds.Right - 1 do
    214     begin
    215       if xb > bounds.left then
    216       begin
    217         for n := DiffPixelArrayLineStart[mindy+blurOfs.Y] to DiffPixelArrayLineStart[maxdy+blurOfs.Y+1]-1 do
    218         begin
    219           pt := DiffPixelOfs[n];
    220           bmpX := xb-blurOfs.X+pt.x;
     191      inc(ppixel);
     192    end;
     193
     194    //compute average
     195    if (Adiv <= 0) {$ifdef PARAM_MASKSHIFT} or (RGBdiv <= 0) {$endif} then
     196      pdest^ := BGRAPixelTransparent
     197    else
     198      pdest^ := computeAverage;
     199
     200    nDiffStart := DiffPixelArrayLineStart[mindy+blurOfs.Y];
     201    nDiffCount := DiffPixelArrayLineStart[maxdy+blurOfs.Y+1]-nDiffStart;
     202
     203    if nDiffCount < nCount then
     204    begin
     205      for xb := bounds.Left+1 to Bounds.Right - 1 do
     206      begin
     207        Inc(pdest);
     208        inc(bmpXBase);
     209        inc(psrc,sizeof(TBGRAPixel));
     210
     211        ppixel:= @DiffPixel[nDiffStart];
     212        for n := nDiffCount-1 downto 0 do
     213        begin
     214          bmpX := bmpXBase+ppixel^.Coord.x;
    221215          if (bmpX >= 0) and (bmpX < bmpWidth) then
    222216          begin
    223             tempPixel := (curScans[pt.y]+bmpX)^;
    224             maskAlpha := DiffPixelWeight[n];
     217            tempPixel := PBGRAPixel(psrc + ppixel^.PtrOfs)^;
     218            maskAlpha := ppixel^.Weight;
    225219            pixMaskAlpha := maskAlpha * tempPixel.alpha;
    226220            sumA    += pixMaskAlpha;
     
    236230            {$hints on}
    237231          end;
    238         end;
    239       end;
    240 
    241       //compute average
    242       if (Adiv <= 0) {$ifdef PARAM_MASKSHIFT} or (RGBdiv <= 0) {$endif} then
    243         pdest^ := BGRAPixelTransparent
    244       else
    245         pdest^ := computeAverage;
    246 
    247       Inc(pdest);
    248     end;
    249 
    250     ShiftScan(yb-blurOfs.Y+maskHeight);
     232          inc(ppixel);
     233        end;
     234
     235        //compute average
     236        if (Adiv <= 0) {$ifdef PARAM_MASKSHIFT} or (RGBdiv <= 0) {$endif} then
     237          pdest^ := BGRAPixelTransparent
     238        else
     239          pdest^ := ComputeAverage;
     240      end;
     241    end else
     242    begin
     243      for xb := bounds.Left+1 to Bounds.Right - 1 do
     244      begin
     245        Inc(pdest);
     246        inc(bmpXBase);
     247        inc(psrc,sizeof(TBGRAPixel));
     248
     249        sumR   := 0;
     250        sumG   := 0;
     251        sumB   := 0;
     252        sumA   := 0;
     253        Adiv   := 0;
     254        {$ifdef PARAM_MASKSHIFT}
     255        RGBdiv := 0;
     256        {$endif}
     257
     258        ppixel:= @Pixel[nStart];
     259        for n := nCount-1 downto 0 do
     260        begin
     261          bmpX := bmpXBase+ppixel^.Coord.x;
     262          //check horizontal range
     263          if (bmpX >= 0) and (bmpX < bmpWidth) then
     264          begin
     265            tempPixel := PBGRAPixel(psrc + ppixel^.PtrOfs)^;
     266            maskAlpha := ppixel^.Weight;
     267            pixMaskAlpha := maskAlpha * tempPixel.alpha;
     268            sumA    += pixMaskAlpha;
     269            Adiv    += maskAlpha;
     270            {$ifdef PARAM_MASKSHIFT}
     271            pixMaskAlpha := pixMaskAlpha shr maskShift;
     272            RGBdiv  += pixMaskAlpha;
     273            {$endif}
     274            {$hints off}
     275            sumR    += tempPixel.red * pixMaskAlpha;
     276            sumG    += tempPixel.green * pixMaskAlpha;
     277            sumB    += tempPixel.blue * pixMaskAlpha;
     278            {$hints on}
     279          end;
     280          inc(ppixel);
     281        end;
     282
     283        //compute average
     284        if (Adiv <= 0) {$ifdef PARAM_MASKSHIFT} or (RGBdiv <= 0) {$endif} then
     285          pdest^ := BGRAPixelTransparent
     286        else
     287          pdest^ := computeAverage;
     288      end;
     289    end;
     290
     291    inc(bmpYBase);
    251292  end;
    252293  ADestination.InvalidateBitmap;
Note: See TracChangeset for help on using the changeset viewer.