Changing color of Bitmap label inside the code.

 
Hello every one.

I wanted to change the color of a bitmap label inside my code, is there any way to do that? attach is a example of shape I put on the chart and I want to change its color.

Thanks for you help in advance.


 

A bitmap derives its appearance from the bitmap file that defines it in RGB pixels.

You can't change its colour as normal graphic objects.

You have to use a different bitmap of another colour or implement canvas rendering yourself.

 
How do I implement convas rendering? 
I don't want to use another bitmap. I want to be able to change its color to whatever color is selected in indicator input. There are millions of color. I cannot have a different bitmap file for each color.
 
Fatemeh Ameri #:
How do I implement convas rendering? 
I don't want to use another bitmap. I want to be able to change its color to whatever color is selected in indicator input. There are millions of color. I cannot have a different bitmap file for each color.

You can , consult this example . 

The broad description of this is :

  • Open the bitmap 
  • Read the pixels 
  • Extract a mask
  • Use that mask to change the color

The code looks sloppy i apologize in advance,  i tried to explain as much as possible in the comments.

#property copyright "Read The Discussion"
#property link      "https://www.mql5.com/en/forum/440152"
#property version   "1.00"

int OnInit()
  {
//---
  //you probably know which bitmap you are loading 
    string filename="\\Files\\boxy.bmp";
    //free the resource
    ResourceFree("MyBoxy");
    //create a new resource from the file
    ResetLastError();
    bool create_from_file=ResourceCreate("MyBoxy",filename);
    if(create_from_file){
    uint pixels[],width=0,height=0;
    //this will send the pixel data to the array and the width height to width and height :P
    ResetLastError();
    bool read_pixels=ResourceReadImage("::MyBoxy",pixels,width,height);
    if(read_pixels){
    /* now you have the pixels so you can loop in them and read the "mask" of the file
       you can decide what the "mask" is .
       So your uint pixel values are Alpha , Red , Green , Blue
       Let's do a silly mask extraction , a naive one 
       We will define a color that represents the void 
       and any deviation from that color will be the intensity of the re-coloration
       So , i want black Red=0 Green=0 Blue=0 to be the void , and on top of that
       if the image is transparent i will adjust the intensity on top 
       A color channel ranges between 0 and 255 with 0 being the lowest value 
                                      and 255 being the maximum value
       So the uint of the pixels contains 4 channels which are 4 bytes which are 4 uchar values
       Nikolai Semko has a nice trick with colors where he uses a union type 
       which turns your code into a lamborghini engine , but for now 
       we will keep it simple.       
       To extract all the channels from a uint we do this : (this may be corrected later)   
    */
    //lets take the first pixel
    uint full_color=pixels[0];
    //alpha sits at the leftmost byte so if we move it to the right by 3 bytes (or 24 bits ) we get its value from 0->255
    uchar alpha=(uchar)(full_color>>24);
    //if you recall typewriters what we just did is move the typewriter header across and threw the rest of the data out , leaving the alpha only
    //now the red we need to move 1 byte to the left to throw the alpha out and then again 3 bytes to the right
    uchar red=(uchar)((full_color<<8)>>24);
    //the green 2 bytes to the left 3 bytes to the right
    uchar green=(uchar)((full_color<<16)>>24);
    //the blue 3 bytes to the left 3 bytes to the right
    uchar blue=(uchar)((full_color<<24)>>24);
    //could this be done with subtractions ? Yes 
    //so now that we know how to read colors lets create a map of intensity 
      uchar map[];
    //and lets resize it to the pixels (the # of pixels)
      ArrayResize(map,ArraySize(pixels),0);
    //and lets set its default value to 0
      ArrayFill(map,0,ArraySize(map),0);
    //cool the map is also from 0 to 255 and this will be the alpha value on our output 
    //let's define our void color levels
      uchar void_red=0,void_green=0,void_blue=0;
      //and let's grab the max red max green and max blue tp be able to adjust the alpha properly at the end
        uchar max_red=0,max_green=0,max_blue=0;
        for(int i=0;i<ArraySize(pixels);i++){
           red=(uchar)((pixels[i]<<8)>>24);
           green=(uchar)((pixels[i]<<16)>>24);
           blue=(uchar)((pixels[i]<<24)>>24);
           if(red>max_red){max_red=red;}
           if(green>max_green){max_green=green;}
           if(blue>max_blue){max_blue=blue;}
           }
      //so lets scan the pixels 
        for(int i=0;i<ArraySize(pixels);i++){
        alpha=(uchar)(pixels[i]>>24);
        red=(uchar)((pixels[i]<<8)>>24);
        green=(uchar)((pixels[i]<<16)>>24);
        blue=(uchar)((pixels[i]<<24)>>24);
        //great , check one how far is this color from the void
        //! keep in mind this is not taking color theory into account
          /*
          we will calculate the deviation of each color channel from the 
          void color , if you are a photographer you will cringe at this point 
          but we are not photographers so :
          max deviation is 255 or in our channels case , their max
          we get the absolute distance of the current red from the void red 
          and divide by the max distance :
          */
          double red_deviation=MathAbs(red-void_red)/((double)max_red);
          double green_deviation=MathAbs(green-void_green)/((double)max_green);
          double blue_deviation=MathAbs(blue-void_blue)/((double)max_blue);
          /*
          we have 3 deviations , let's make photographers cringe more 
          each one is 1 third of the total deviation
          */
          double deviation=(red_deviation+green_deviation+blue_deviation)/3.00;
          //and this is our initial intensity which can only be curbed by the alpha channel
          /* how ? if the alpha is half transparent for instance 
                   it will be 127 , so that will result in an alpha curb of 0.5
                   which we will plaster all over our deviation .
                   
          */
          double alpha_curb=((double)alpha)/255.0;
          double intensity=alpha_curb*deviation;
          //and the map has values from 0-255 
                 intensity*=255.0;
          map[i]=(uchar)(intensity);
          //this part is done 
        }
        /*we exit the loop with a mask (map[])
          that mask is telling us , go ahead and create a color with rgb
          and set the alpha to this value and you are good to go
        */
        //so let's define our color 
          uchar new_red=0,new_green=255,new_blue=0;
        //we could also use a base color 
          //so loop into pixels and change them
            for(int i=0;i<ArraySize(pixels);i++){
            //if we use a base color we can use this handy function of mql5
              uint new_color=ColorToARGB(clrGreen,map[i]);
            //or if we use our channels we can 
                   new_color=(((uint)map[i])<<24)|(((uint)new_red)<<16)|(((uint)new_green)<<8)|((uint)new_blue);
              pixels[i]=new_color;
            }
        //done , now we need to update the resource 
          ResourceFree("MyBoxy");
          //recreate from pixels 
            ResetLastError();
            bool recreate=ResourceCreate("MyBoxy",pixels,width,height,0,0,width,COLOR_FORMAT_ARGB_NORMALIZE);
            if(recreate){
            //create a bitmap label 
              ObjectCreate(ChartID(),"MyBoxies1",OBJ_BITMAP_LABEL,0,0,0);
              ObjectSetInteger(ChartID(),"MyBoxies1",OBJPROP_XSIZE,width);
              ObjectSetInteger(ChartID(),"MyBoxies1",OBJPROP_YSIZE,height);
              ObjectSetString(ChartID(),"MyBoxies1",OBJPROP_BMPFILE,"::MyBoxy");
              ChartRedraw();
            }else{
            Print("Cannot recreate resource "+IntegerToString(GetLastError()));
            }
        
    }else{Print("Cannot read resource pixels "+IntegerToString(GetLastError()));}
    }else{Print("Cannot create resource from file "+IntegerToString(GetLastError()));}
//---
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
  ObjectsDeleteAll(ChartID(),"MyBoxies"); 
  }
void OnTick()
  {

  }
 
Fatemeh Ameri #: How do I implement convas rendering? I don't want to use another bitmap. I want to be able to change its color to whatever color is selected in indicator input. There are millions of color. I cannot have a different bitmap file for each color.

Use the custom graphics or canvas from the MQL5 Standard Library: Documentation on MQL5: Standard Library / Custom Graphics / CCanvas

However, from your screenshot you seem to be using MQL4 (you posted in the wrong section), which also has a Standard Library but it is much more limited and has not been updated for a long time. There is also no documentation for the MQL4 Standard Library, so you will have to rely on the MQL5 documentation which will not always match.

You will also find more information about it in Articles and CodeBase:

Articles: https://www.mql5.com/en/search#!keyword=ccanvas&module=mql5_module_articles

CodeBase: https://www.mql5.com/en/search#!keyword=CCanvas&module=mql5_module_codebase

 
Fernando Carreiro #:

Use the custom graphics or canvas from the MQL5 Standard Library: Documentation on MQL5: Standard Library / Custom Graphics / CCanvas

However, from your screenshot you seem to be using MQL4 (you posted in the wrong section), which also has a Standard Library but it is much more limited and has not been updated for a long time. There is also no documentation for the MQL4 Standard Library, so you will have to rely on the MQL5 documentation which will not always match.

You will also find more information about it in Articles and CodeBase:

Articles: https://www.mql5.com/en/search#!keyword=ccanvas&module=mql5_module_articles

CodeBase: https://www.mql5.com/en/search#!keyword=CCanvas&module=mql5_module_codebase

Thank you very much for your help.

 
Lorentzos Roussos #:

You can , consult this example . 

The broad description of this is :

  • Open the bitmap 
  • Read the pixels 
  • Extract a mask
  • Use that mask to change the color

The code looks sloppy i apologize in advance,  i tried to explain as much as possible in the comments.

Thanks for you code, actually I could read the bitmap file using ResourceReadImage() function and I could change the size of it, but I could not change the file color no matter whatever I tried.

 
Fatemeh Ameri #:

Thanks for you code, actually I could read the bitmap file using ResourceReadImage() function and I could change the size of it, but I could not change the file color no matter whatever I tried.

You cannot change the color with this code ? 

 
Lorentzos Roussos #:

You cannot change the color with this code ? 

Ni I could not, I tried to use your code, but I could not figure it out, It gives some errors. But I managed to change the bitmap file size using below code, can you guide me how I can change the color? (Many thanks in advance)

 
#resource  "\\Images\\Rect.bmp"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetTimer(60);
  // Bitmap_Label(0,"name1",0,20,20,"::Resources\\rect1.bmp",NULL);
  // Bitmap_Label(0,"name2",0,100,120,"::Resources\\AAA.bmp",NULL);
  //you probably know which bitmap you are loading 
   const string myIcons = "::Images\\Rect.bmp"; //icons resource name
   const string newIcon = "Files\\Rect_Small_new.bmp"; //new resource name
   
   uint data[];    //array to store image data
   int imageW = 0; //variable to store image data width
   int imageH = 0; //variable to store image height
   ResourceReadImage( myIcons, data, imageW, imageH ); //Read Image Data;
   //Print("imageW: ",imageW," imageH: ",imageH);
   ResourceCreate( newIcon, data, 100, 100, 15 , 15 , imageW, COLOR_FORMAT_ARGB_NORMALIZE ); //Create a new smaller image
   
   ResourceSave( newIcon,"Rect_Small_new.bmp" );  //Save the image to file 

  
   //Rectangle_label(0,"resd",0,20,20,200,200);
//---
   return(INIT_SUCCEEDED);
  }
The actual file size was like 150*150 . I changed it to 100*100. I must change the "data" from ResourceReadImage to change the file color, but I cannot figure it out how.
 
Fatemeh Ameri #:

Ni I could not, I tried to use your code, but I could not figure it out, It gives some errors. But I managed to change the bitmap file size using below code, can you guide me how I can change the color? (Many thanks in advance)

The actual file size was like 150*150 . I changed it to 100*100. I must change the "data" from ResourceReadImage to change the file color, but I cannot figure it out how.

What error did you get ?

If its an alpha channel ARGB bmp try this :

#resource "\\Files\\boxy.bmp";
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
  uint getWidth=0,getHeight=0;
  if(reColorWithAlphaMask("Files\\boxy.bmp",clrCrimson,255,true,getWidth,getHeight)){
            //create a bitmap label 
              ObjectCreate(ChartID(),"MyBoxies1",OBJ_BITMAP_LABEL,0,0,0);
              ObjectSetInteger(ChartID(),"MyBoxies1",OBJPROP_XSIZE,getWidth);
              ObjectSetInteger(ChartID(),"MyBoxies1",OBJPROP_YSIZE,getHeight);
              ObjectSetString(ChartID(),"MyBoxies1",OBJPROP_BMPFILE,"::Files\\boxy.bmp");
              ChartRedraw();  
  }else{
  Print("Cannot recolor");
  }
   
//---
   return(INIT_SUCCEEDED);
  }
  
  
bool reColorWithAlphaMask(string _resource_name,
                          color newColor,
                          uchar maxOpacity,
                          bool maintainOriginalAlpha,
                          uint &_result_width,
                          uint &_result_height){
     //read image 
       uint pixels[];
       _result_width=0;
       _result_height=0;
       if(ResourceReadImage("::"+_resource_name,pixels,_result_width,_result_height)){
       uchar max_alpha=255,min_alpha=0;
       //pass 1 : get min max if not original opacity
         if(!maintainOriginalAlpha){
         max_alpha=0;min_alpha=255;
         for(int i=0;i<ArraySize(pixels);i++){
         uchar this_alpha=(uchar)(pixels[i]>>24);
         if(this_alpha>max_alpha){max_alpha=this_alpha;}
         if(this_alpha<min_alpha){min_alpha=this_alpha;}
         if(max_alpha==255&&min_alpha==0){break;}
         }
         }
       //map it 
         uchar map[];
         ArrayResize(map,ArraySize(pixels),0);
         for(int i=0;i<ArraySize(pixels);i++){
         uchar this_alpha=(uchar)(pixels[i]>>24);
         map[i]=(uchar)((((double)(this_alpha-min_alpha))/MathMax(1,max_alpha-min_alpha))*maxOpacity);
         }
       //recolor it 
         for(int i=0;i<ArraySize(pixels);i++){
         uint col=ColorToARGB(newColor,map[i]);
         pixels[i]=col;
         }
       //reresource
         ResourceFree(_resource_name);
         if(ResourceCreate(_resource_name,pixels,_result_width,_result_height,0,0,_result_width,COLOR_FORMAT_ARGB_NORMALIZE)){
         return(true);
         }
       }else{
       Print("reColor cannot read resource "+_resource_name);
       }
     return(false);
     }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  ObjectsDeleteAll(ChartID(),"MyBoxies");  
  }

in your code 

#resource  "\\Images\\Rect.bmp"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetTimer(60);
  // Bitmap_Label(0,"name1",0,20,20,"::Resources\\rect1.bmp",NULL);
  // Bitmap_Label(0,"name2",0,100,120,"::Resources\\AAA.bmp",NULL);
  //you probably know which bitmap you are loading 
   const string myIcons = "::Images\\Rect.bmp"; //icons resource name
   const string newIcon = "Files\\Rect_Small_new.bmp"; //new resource name
   
   uint data[];    //array to store image data
   int imageW = 0; //variable to store image data width
   int imageH = 0; //variable to store image height
   ResourceReadImage( myIcons, data, imageW, imageH ); //Read Image Data;
   //Print("imageW: ",imageW," imageH: ",imageH);
   ResourceCreate( newIcon, data, 100, 100, 15 , 15 , imageW, COLOR_FORMAT_ARGB_NORMALIZE ); //Create a new smaller image
   uint getWidth=0,getHeight=0;
   reColorWithAlphaMask(newIcon,clrCrimson,255,true,getWidth,getHeight);   
   ResourceSave( newIcon,"Rect_Small_new.bmp" );  //Save the image to file 

  
   //Rectangle_label(0,"resd",0,20,20,200,200);
//---
   return(INIT_SUCCEEDED);
  }
 
Lorentzos Roussos #:

What error did you get ?

If its an alpha channel ARGB bmp try this :

Oh my god, It works, Thank you 1000 times.