// Constructor public PixelColor(PixelColor p, byte a) { // Initialize this.a = a; this.r = p.r; this.g = p.g; this.b = p.b; }
// This makes a color gray public static PixelColor Desaturate(PixelColor a) { float ar = (float)a.r * BYTE_TO_FLOAT; float ag = (float)a.g * BYTE_TO_FLOAT; float ab = (float)a.b * BYTE_TO_FLOAT; float l = (ar * 0.3f) + (ag * 0.59f) + (ab * 0.11f); PixelColor c = new PixelColor(); c.a = a.a; c.r = (byte)(l * 255.0f); c.g = (byte)(l * 255.0f); c.b = (byte)(l * 255.0f); return c; }
// This modulates two colors public static PixelColor Add(PixelColor a, PixelColor b) { float aa = (float)a.a * BYTE_TO_FLOAT; float ar = (float)a.r * BYTE_TO_FLOAT; float ag = (float)a.g * BYTE_TO_FLOAT; float ab = (float)a.b * BYTE_TO_FLOAT; float ba = (float)b.a * BYTE_TO_FLOAT; float br = (float)b.r * BYTE_TO_FLOAT; float bg = (float)b.g * BYTE_TO_FLOAT; float bb = (float)b.b * BYTE_TO_FLOAT; PixelColor c = new PixelColor(); c.a = (byte)(Tools.Clamp(aa + ba, 0.0f, 1.0f) * 255.0f); c.r = (byte)(Tools.Clamp(ar + br, 0.0f, 1.0f) * 255.0f); c.g = (byte)(Tools.Clamp(ag + bg, 0.0f, 1.0f) * 255.0f); c.b = (byte)(Tools.Clamp(ab + bb, 0.0f, 1.0f) * 255.0f); return c; }
// This blends two colors with respect to alpha public PixelColor Blend(PixelColor a, PixelColor b) { PixelColor c = new PixelColor(); float ba; ba = (float)a.a * BYTE_TO_FLOAT; c.r = (byte)((float)a.r * (1f - ba) + (float)b.r * ba); c.g = (byte)((float)a.g * (1f - ba) + (float)b.g * ba); c.b = (byte)((float)a.b * (1f - ba) + (float)b.b * ba); c.a = (byte)((float)a.a * (1f - ba) + ba); return c; }
// This modulates two colors public static PixelColor Scale(PixelColor a, float scalar) { float ar = (float)a.r * BYTE_TO_FLOAT; float ag = (float)a.g * BYTE_TO_FLOAT; float ab = (float)a.b * BYTE_TO_FLOAT; PixelColor c = new PixelColor(); c.a = a.a; c.r = (byte)(Tools.Clamp(ar * scalar, 0.0f, 1.0f) * 255.0f); c.g = (byte)(Tools.Clamp(ag * scalar, 0.0f, 1.0f) * 255.0f); c.b = (byte)(Tools.Clamp(ab * scalar, 0.0f, 1.0f) * 255.0f); return c; }
// This modulates two colors public static PixelColor Modulate(PixelColor a, PixelColor b) { float aa = (float)a.a * BYTE_TO_FLOAT; float ar = (float)a.r * BYTE_TO_FLOAT; float ag = (float)a.g * BYTE_TO_FLOAT; float ab = (float)a.b * BYTE_TO_FLOAT; float ba = (float)b.a * BYTE_TO_FLOAT; float br = (float)b.r * BYTE_TO_FLOAT; float bg = (float)b.g * BYTE_TO_FLOAT; float bb = (float)b.b * BYTE_TO_FLOAT; PixelColor c = new PixelColor(); c.a = (byte)((aa * ba) * 255.0f); c.r = (byte)((ar * br) * 255.0f); c.g = (byte)((ag * bg) * 255.0f); c.b = (byte)((ab * bb) * 255.0f); return c; }
// Linear interpolation public static PixelColor Lerp(PixelColor a, PixelColor b, float u) { float aa = (float)a.a * BYTE_TO_FLOAT; float ar = (float)a.r * BYTE_TO_FLOAT; float ag = (float)a.g * BYTE_TO_FLOAT; float ab = (float)a.b * BYTE_TO_FLOAT; float ba = (float)b.a * BYTE_TO_FLOAT; float br = (float)b.r * BYTE_TO_FLOAT; float bg = (float)b.g * BYTE_TO_FLOAT; float bb = (float)b.b * BYTE_TO_FLOAT; PixelColor c = new PixelColor(); c.a = (byte)(((ba * u) + (aa * (1.0f - u))) * 255.0f); c.r = (byte)(((br * u) + (ar * (1.0f - u))) * 255.0f); c.g = (byte)(((bg * u) + (ag * (1.0f - u))) * 255.0f); c.b = (byte)(((bb * u) + (ab * (1.0f - u))) * 255.0f); return c; }
// Background downloading and processing private unsafe void UpdateThread() { HttpWebResponse webresponse = null; bool failed = false; string failmsg = ""; Image downloadimg = null; DateTime starttime = new DateTime(); // Make the GET request HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(ADDRESS); webrequest.Referer = REFERRER; webrequest.Method = "GET"; webrequest.KeepAlive = false; webrequest.Timeout = 5000; webrequest.UserAgent = "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 GTB5 (.NET CLR 3.5.30729)"; webrequest.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); try { // Download! webresponse = (HttpWebResponse)webrequest.GetResponse(); } catch (Exception e) { failed = true; failmsg = "Failed to update buienradar. Web request " + e.GetType().Name + ": " + e.Message; webresponse = null; } if (!failed) { try { // Make image downloadimg = Image.FromStream(webresponse.GetResponseStream()); webresponse.Close(); } catch (Exception e) { failed = true; failmsg = "Failed to update buienradar. Image read " + e.GetType().Name + ": " + e.Message; downloadimg = null; } } if (!failed) { // Dispose old images if (images != null) { for (int i = 0; i < images.Length; i++) { if (images[i] != null) { images[i].Dispose(); } } } images = null; arrowlocations = null; //#if !DEBUG try { //#endif // Time at which the animation starts DateTime now = DateTime.Now.AddMinutes(ADJUST_TIME_MINUTES); int nearest5min = (int)(Math.Round((double)now.Minute / (double)5) * (double)5); starttime = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0); starttime = starttime.AddMinutes(nearest5min); // Prepare variables to track the rain DateTime incomingtime = new DateTime(); bool isincoming = false; DateTime cleartime = new DateTime(); int clearframecount = 0; // Disassemble the image into separate images FrameDimension fd = new FrameDimension(downloadimg.FrameDimensionsList[0]); int numimages = downloadimg.GetFrameCount(fd); images = new Image[numimages]; downloadimg.SelectActiveFrame(fd, 0); Bitmap firstbmp = new Bitmap(downloadimg); Size sz = firstbmp.Size; BitmapData firstbmpdata = firstbmp.LockBits(new Rectangle(0, 0, sz.Width, sz.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); for (int i = 0; i < numimages; i++) { downloadimg.SelectActiveFrame(fd, i); Bitmap imgbmp = new Bitmap(downloadimg); Bitmap newbmp = new Bitmap(sz.Width, sz.Height, PixelFormat.Format32bppArgb); // Start processing the image BitmapData imgbmpdata = imgbmp.LockBits(new Rectangle(0, 0, sz.Width, sz.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData newbmpdata = newbmp.LockBits(new Rectangle(0, 0, sz.Width, sz.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); PixelColor *fpixels = (PixelColor *)(firstbmpdata.Scan0.ToPointer()); PixelColor *ipixels = (PixelColor *)(imgbmpdata.Scan0.ToPointer()); PixelColor *npixels = (PixelColor *)(newbmpdata.Scan0.ToPointer()); // Go for all pixels bool wholeframeclear = true; for (int y = 0; y < sz.Height; y++) { for (int x = 0; x < sz.Width; x++) { // We compare the pixel of the first image (no clouds) with // the current image to determine if there are clouds here bool isclear = (ipixels->b == fpixels->b) && (ipixels->g == fpixels->g) && (ipixels->r == fpixels->r); // Detect rain at current location if (!isclear && (x >= LOCATION_X - LOCATION_RADIUS) && (x <= LOCATION_X + LOCATION_RADIUS) && (y >= LOCATION_Y - LOCATION_RADIUS) && (y <= LOCATION_Y + LOCATION_RADIUS) && (i > 0)) { wholeframeclear = false; if (!isincoming) { // Rain! incomingtime = starttime.AddMinutes(i * 10); isincoming = true; clearframecount = 0; } if (clearframecount < CLEAR_FRAMES) { clearframecount = 0; } } // Clear pixel? if (isclear) { // This pixel is normal. PixelColor ds = PixelColor.Desaturate(*ipixels); * npixels = PixelColor.Lerp(ds, *ipixels, 0.1f); * npixels = PixelColor.Scale(*npixels, 1.1f); PixelColor add = new PixelColor(0, 10, 10, 10); * npixels = PixelColor.Add(*npixels, add); } else { // This pixel is a cloud. PixelColor mod = new PixelColor(255, 160, 160, 250); * npixels = PixelColor.Modulate(*ipixels, mod); * npixels = PixelColor.Scale(*npixels, 1.8f); } // Next pixel fpixels++; ipixels++; npixels++; } } // Whole frame clear of rain at current location? if (wholeframeclear) { // Count this frame as a clear frame clearframecount++; if (clearframecount == CLEAR_FRAMES) { // The clear time is 3 frames ago cleartime = starttime.AddMinutes((i - 3) * 10); } } // Clean up imgbmp.UnlockBits(imgbmpdata); newbmp.UnlockBits(newbmpdata); images[i] = newbmp; imgbmp.Dispose(); imgbmp = null; } // Show incoming time if (isincoming) { incomingtext = incomingtime.Hour + ":" + incomingtime.Minute.ToString("00"); flashincoming = true; } else { incomingtext = "N / A"; flashincoming = false; } // Show clear time if (clearframecount >= CLEAR_FRAMES) { cleartext = cleartime.Hour + ":" + cleartime.Minute.ToString("00"); flashclear = true; } else { cleartext = "N / A"; flashclear = false; } // Clean up firstbmp.UnlockBits(firstbmpdata); firstbmp.Dispose(); firstbmp = null; downloadimg.Dispose(); downloadimg = null; //#if !DEBUG } catch (Exception e) { failed = true; failmsg = "Failed to update buienradar. Image processing " + e.GetType().Name + ": " + e.Message; downloadimg = null; } //#endif if (images != null) { // Set up some random arrow locations, for decorative reason Random rnd = new Random(); arrowlocations = new Size[images.Length]; Size offset = new Size(radar.Left + 100 + rnd.Next(radar.Width - movearrow1.Width - 100), radar.Top + 100 + rnd.Next(radar.Height - movearrow1.Height - 100)); for (int i = 0; i < images.Length; i++) { arrowlocations[i] = offset + new Size(rnd.Next(100) - 50, rnd.Next(100) - 50); } } // Done firstimagetime = starttime; nextupdatedelay = NORMAL_UPDATE_DELAY; } // Handle failure if (failed) { HandleFail(failmsg); } else { updatefailed = false; } // We're done updating (either successful or failed) UpdateComplete(); }
// Background downloading and processing private unsafe void UpdateThread() { HttpWebResponse webresponse = null; bool failed = false; string failmsg = ""; Image downloadimg = null; DateTime starttime = new DateTime(); // Make the GET request HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(ADDRESS); webrequest.Referer = REFERRER; webrequest.Method = "GET"; webrequest.KeepAlive = false; webrequest.Timeout = 5000; webrequest.UserAgent = "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 GTB5 (.NET CLR 3.5.30729)"; webrequest.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); try { // Download! webresponse = (HttpWebResponse)webrequest.GetResponse(); } catch(Exception e) { failed = true; failmsg = "Failed to update buienradar. Web request " + e.GetType().Name + ": " + e.Message; webresponse = null; } if(!failed) { try { // Make image downloadimg = Image.FromStream(webresponse.GetResponseStream()); webresponse.Close(); } catch(Exception e) { failed = true; failmsg = "Failed to update buienradar. Image read " + e.GetType().Name + ": " + e.Message; downloadimg = null; } } if(!failed) { // Dispose old images if(images != null) { for(int i = 0; i < images.Length; i++) if(images[i] != null) images[i].Dispose(); } images = null; arrowlocations = null; //#if !DEBUG try { //#endif // Time at which the animation starts DateTime now = DateTime.Now.AddMinutes(ADJUST_TIME_MINUTES); int nearest5min = (int)(Math.Round((double)now.Minute / (double)5) * (double)5); starttime = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0); starttime = starttime.AddMinutes(nearest5min); // Prepare variables to track the rain DateTime incomingtime = new DateTime(); bool isincoming = false; DateTime cleartime = new DateTime(); int clearframecount = 0; // Disassemble the image into separate images FrameDimension fd = new FrameDimension(downloadimg.FrameDimensionsList[0]); int numimages = downloadimg.GetFrameCount(fd); images = new Image[numimages]; downloadimg.SelectActiveFrame(fd, 0); Bitmap firstbmp = new Bitmap(downloadimg); Size sz = firstbmp.Size; BitmapData firstbmpdata = firstbmp.LockBits(new Rectangle(0, 0, sz.Width, sz.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); for(int i = 0; i < numimages; i++) { downloadimg.SelectActiveFrame(fd, i); Bitmap imgbmp = new Bitmap(downloadimg); Bitmap newbmp = new Bitmap(sz.Width, sz.Height, PixelFormat.Format32bppArgb); // Start processing the image BitmapData imgbmpdata = imgbmp.LockBits(new Rectangle(0, 0, sz.Width, sz.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData newbmpdata = newbmp.LockBits(new Rectangle(0, 0, sz.Width, sz.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); PixelColor* fpixels = (PixelColor*)(firstbmpdata.Scan0.ToPointer()); PixelColor* ipixels = (PixelColor*)(imgbmpdata.Scan0.ToPointer()); PixelColor* npixels = (PixelColor*)(newbmpdata.Scan0.ToPointer()); // Go for all pixels bool wholeframeclear = true; for(int y = 0; y < sz.Height; y++) for(int x = 0; x < sz.Width; x++) { // We compare the pixel of the first image (no clouds) with // the current image to determine if there are clouds here bool isclear = (ipixels->b == fpixels->b) && (ipixels->g == fpixels->g) && (ipixels->r == fpixels->r); // Detect rain at current location if(!isclear && (x >= LOCATION_X - LOCATION_RADIUS) && (x <= LOCATION_X + LOCATION_RADIUS) && (y >= LOCATION_Y - LOCATION_RADIUS) && (y <= LOCATION_Y + LOCATION_RADIUS) && (i > 0)) { wholeframeclear = false; if(!isincoming) { // Rain! incomingtime = starttime.AddMinutes(i * 10); isincoming = true; clearframecount = 0; } if(clearframecount < CLEAR_FRAMES) clearframecount = 0; } // Clear pixel? if(isclear) { // This pixel is normal. PixelColor ds = PixelColor.Desaturate(*ipixels); *npixels = PixelColor.Lerp(ds, *ipixels, 0.1f); *npixels = PixelColor.Scale(*npixels, 1.1f); PixelColor add = new PixelColor(0, 10, 10, 10); *npixels = PixelColor.Add(*npixels, add); } else { // This pixel is a cloud. PixelColor mod = new PixelColor(255, 160, 160, 250); *npixels = PixelColor.Modulate(*ipixels, mod); *npixels = PixelColor.Scale(*npixels, 1.8f); } // Next pixel fpixels++; ipixels++; npixels++; } // Whole frame clear of rain at current location? if(wholeframeclear) { // Count this frame as a clear frame clearframecount++; if(clearframecount == CLEAR_FRAMES) { // The clear time is 3 frames ago cleartime = starttime.AddMinutes((i - 3) * 10); } } // Clean up imgbmp.UnlockBits(imgbmpdata); newbmp.UnlockBits(newbmpdata); images[i] = newbmp; imgbmp.Dispose(); imgbmp = null; } // Show incoming time if(isincoming) { incomingtext = incomingtime.Hour + ":" + incomingtime.Minute.ToString("00"); flashincoming = true; } else { incomingtext = "N / A"; flashincoming = false; } // Show clear time if(clearframecount >= CLEAR_FRAMES) { cleartext = cleartime.Hour + ":" + cleartime.Minute.ToString("00"); flashclear = true; } else { cleartext = "N / A"; flashclear = false; } // Clean up firstbmp.UnlockBits(firstbmpdata); firstbmp.Dispose(); firstbmp = null; downloadimg.Dispose(); downloadimg = null; //#if !DEBUG } catch(Exception e) { failed = true; failmsg = "Failed to update buienradar. Image processing " + e.GetType().Name + ": " + e.Message; downloadimg = null; } //#endif if(images != null) { // Set up some random arrow locations, for decorative reason Random rnd = new Random(); arrowlocations = new Size[images.Length]; Size offset = new Size(radar.Left + 100 + rnd.Next(radar.Width - movearrow1.Width - 100), radar.Top + 100 + rnd.Next(radar.Height - movearrow1.Height - 100)); for(int i = 0; i < images.Length; i++) arrowlocations[i] = offset + new Size(rnd.Next(100) - 50, rnd.Next(100) - 50); } // Done firstimagetime = starttime; nextupdatedelay = NORMAL_UPDATE_DELAY; } // Handle failure if(failed) HandleFail(failmsg); else updatefailed = false; // We're done updating (either successful or failed) UpdateComplete(); }