Canvas->CopyRect shifts 1 pixel by zoomed image

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • WRoos
    New Member
    • Oct 2012
    • 7

    Canvas->CopyRect shifts 1 pixel by zoomed image

    I'm building a bitmapmanipulat ion-component in C++Builder6

    After loading a bitmap in my component, I then can make a selection, which can be moved around.

    The problem I have is in my OnPaint-event. I paint the topmost bitmap first(the selection), then find the parts that not have been painted, and paint those parts from the original bitmap.
    If the bitmaps are zoomed-out (smaller on the screen) the original bitmap right to the selection-and selection itself sometimes are distorted.
    I tested this with a Zoom of 4 and found distortion only occurs if the rect.left is odd. If it's even all is well. I tried to shift the bitmaps by odd numbers but then the errors occur when zoomed different.

    This also happen when no rounding errors by zooming occur.

    Can anyone help??
  • Rabbit
    Recognized Expert MVP
    • Jan 2007
    • 12517

    #2
    I don't know anything about image manipulation but I do know that it will be difficult to help without seeing the code that's causing the issue.

    Comment

    • WRoos
      New Member
      • Oct 2012
      • 7

      #3
      Code:
      //I'm using struct: FObject containing: 
      //	bitmap
      //    srect: position on screen
      //    brect: position in bitmap (bitmap's in bitmap's)
      //
      // mylist start with the ClipRect (the invalidated rect for my control)
       OnPaint()
      {
       TRect rmr[5], *todo;
      
       Canvas->CopyMode = cmSrcCopy;
       for (int n=FObjects->Count-1; n>=0; n--) {  // last bitmap first
         have = (TBBObject*) FObjects->Items[n];
      
         for (int m=mylist->Count-1; m>=0; m--) {   
            todo = (TRect*) mylist->Items[m];
            count = RectMinusRect(*todo, shift, rmr);
      	// RectMinusRect return 1-5 rects. 
      	// first one is the one to paint now (the vissible part of todo)
      	// the other contain max 4 left over peaces
            TRect tobmp(rmr[0]);
      	// now I shift to bmp to its place
            OffsetRect(&tobmp, have->srect.left, have->srect.top);
      	// for a zoom of -4 the bitmap-points are all multiplied by 4
            ImgageToBitmap(&tobmp);
      
         	Canvas->CopyRect(rmr[0], have->bitmap->Canvas, tobmp); //(dst,canvas, src)
      
            delete todo;          // this rect is painted and can be deleted
            mylist->Delete(m);
            for (int t=1; t<=count; t++) {   // left over rect's to be painted 
               todo = new TRect(rmr[t]);     // with next have->bitmap
               mylist->Add(todo);
            }
         }
      }
      Last edited by Meetee; Oct 11 '12, 11:02 AM. Reason: use code tags <code/> around your code

      Comment

      • WRoos
        New Member
        • Oct 2012
        • 7

        #4
        I made a compleet program with my problem.
        If someone is willing to help, he/she can take this code in a new project,
        1)define the RMinR function in the .h file
        2)define the FormPaint-event in the Form
        3)run.

        It paints a bitmap in 5 parts. If you look closely you can see the center and the part right to the center are shifted 1 pixel.
        For some bitmaps this is more disturbing then for others.
        if you change thisbmp(21,21,2 01,201) to even numbers
        all goes well.

        Code:
        //---------------------------------------------------------------------------
        void __fastcall TForm1::FormPaint(TObject *Sender)
        {
        Graphics::TBitmap* abmp = new Graphics::TBitmap;
         // a bitmap at least 850x850 pixels
         abmp->LoadFromFile("D:\\CBuilder6\\large.bmp");
         abmp->HandleType = bmDDB; // best quality-bitmap
        TList* rectlist = new TList;
        TRect* todo = new TRect;
        TRect rmr[5], bmprct, thisbmp;
        int count;
         *todo = TRect(0,0,abmp->Width/4,abmp->Height/4);
         rectlist->Add(todo);
        
         Canvas->CopyMode = cmSrcCopy;
         for(int n=0; n<2; n++) {      // 2 bitmap's
           if (n==0) thisbmp = TRect(21,21,201,201);
           else      thisbmp = TRect(0,0,abmp->Width/4,abmp->Height/4);
           for (int m=rectlist->Count-1; m>=0; m--) {
              todo = (TRect*) rectlist->Items[m];
              count = RMinR(*todo, thisbmp, rmr);
              bmprct = rmr[0];
              bmprct.left   *= 4; // Asume zoom = 4
              bmprct.top    *= 4;
              bmprct.right  *= 4;
              bmprct.bottom *= 4;
              // Stretching and copying at the same time
              Canvas->CopyRect(rmr[0], abmp->Canvas, bmprct);
        
              delete todo;
              rectlist->Delete(m);
              for (int t=1; t<=count; t++) {
                 todo = new TRect(rmr[t]);
                 rectlist->Add(todo);
              }
           }
         }
         delete abmp;
         delete rectlist;
         abmp = NULL;
        }
        //---------------------------------------------------------------------------
        int __fastcall TForm1::RMinR(TRect& ToDo, TRect& Have, TRect* Remain)
        {
        int ret = 0;
         if (Have.top > ToDo.top) {
           Remain[++ret] = TRect(ToDo.left, ToDo.top, ToDo.right, Have.top);
           Remain[0].top = Have.top;
         } else Remain[0].top = ToDo.top;
         if (Have.bottom < ToDo.bottom) {
           Remain[++ret] = TRect(ToDo.left, Have.bottom, ToDo.right, ToDo.bottom);
           Remain[0].bottom = Have.bottom;
         } else Remain[0].bottom = ToDo.bottom;
         if (Have.left > ToDo.left) {
           Remain[++ret] = TRect(ToDo.left, Remain[0].top, Have.left, Remain[0].bottom);
           Remain[0].left = Have.left;
         } else Remain[0].left = ToDo.left;
         if (Have.right < ToDo.right) {
           Remain[++ret] = TRect(Have.right, Remain[0].top, ToDo.right, Remain[0].bottom);
           Remain[0].right = Have.right;
         } else Remain[0].right = ToDo.right;
        // if (Remain[0].left > 0 && Remain[0].left%2 == 1) {Remain[0].left--; Remain[0].right--;}
         return ret;
        }
        Last edited by Niheel; Oct 11 '12, 07:35 PM.

        Comment

        Working...