Last active
March 16, 2022 12:48
-
-
Save alexrainman/33379b672be8f5877c5d to your computer and use it in GitHub Desktop.
Xamarin Android light sensor class (easy portable to Java)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Android.Graphics; | |
using Android.Hardware; | |
using Android.Media; | |
using Java.IO; | |
using YourNamespace.Utils; | |
namespace YourNamespace | |
{ | |
public class LightMeter: Java.Lang.Object, Android.Hardware.Camera.IPictureCallback, Android.Hardware.Camera.IPreviewCallback | |
{ | |
/* | |
* You can estimate the reflected light by taking a picture with your camera, and glancing at the exposure at given settings. | |
* If the exposure is decent, look at the meter settings: your used ISO, aperture, and shutter speed. | |
* Once you have a reading, you can do two conversions to reach the approximate LUX value. | |
* First, you need to convert to an EV (Exposure Value), then to LUX. | |
*/ | |
int cameraId; | |
Android.Hardware.Camera camera; | |
string PICTURE_FILENAME = ""; | |
public void Start() { | |
try{ | |
cameraId = findFrontFacingCamera(); | |
if (camera == null) { | |
camera = Android.Hardware.Camera.Open(cameraId); | |
Android.Hardware.Camera.Parameters p = camera.GetParameters(); | |
p.PictureFormat = ImageFormatType.Jpeg; | |
p.Set("ISO", 100); | |
camera.SetParameters(p); | |
camera.Lock(); | |
SurfaceTexture surfaceTexture = new SurfaceTexture(10); | |
camera.SetPreviewTexture(surfaceTexture); | |
camera.StartPreview(); | |
} | |
} | |
catch(IOException e){ | |
} | |
} | |
public void Stop() { | |
try { | |
if (camera != null) { | |
camera.StopPreview (); | |
camera.SetPreviewDisplay (null); | |
camera.SetPreviewCallback (null); | |
camera.Unlock (); | |
camera.Release (); | |
camera = null; | |
} | |
} catch (IOException ex) { | |
} | |
} | |
int findFrontFacingCamera() { | |
Android.Hardware.Camera.CameraInfo camInfo = new Android.Hardware.Camera.CameraInfo (); | |
for (int i = 0; i < Android.Hardware.Camera.NumberOfCameras; i++) { | |
Android.Hardware.Camera.GetCameraInfo (i, camInfo); | |
if (camInfo.Facing == CameraFacing.Front){ | |
try { | |
return i; | |
} catch (Exception e) { | |
// log or something | |
} | |
} | |
} | |
return -1; | |
} | |
public void TakePicture(){ | |
if (camera != null) { | |
camera.TakePicture (null, this, this); | |
} | |
} | |
public double GetLux(){ | |
/* Illuminance Surfaces illuminated by: | |
* | |
* 0.0001 lux Moonless, overcast night sky (starlight)[3] | |
* 0.002 lux Moonless clear night sky with airglow[3] | |
* 0.27–1.0 lux Full moon on a clear night[3][4] | |
* 3.4 lux Dark limit of civil twilight under a clear sky[5] | |
* 50 lux Family living room lights (Australia, 1998)[6] | |
* 80 lux Office building hallway/toilet lighting[7][8] | |
* 100 lux Very dark overcast day[3] | |
* 320–500 lux Office lighting[9][10][11] | |
* 400 lux Sunrise or sunset on a clear day. | |
* 1000 lux Overcast day;[3] typical TV studio lighting | |
* 10000–25000 lux Full daylight (not direct sun)[3] | |
* 32000–100000 lux Direct sunlight | |
*/ | |
ExifInterface exif = null; | |
if (!PICTURE_FILENAME.Equals("")){ | |
try { | |
File dataDir = Android.OS.Environment.ExternalStorageDirectory; | |
exif = new ExifInterface(dataDir + "/" + PICTURE_FILENAME); | |
} catch (IOException ex) { | |
} | |
} | |
if (exif != null) { | |
PICTURE_FILENAME = ""; | |
// (Exposure Value) EV = log2 N2 / t | |
/* where: | |
* N is the relative aperture (f-number) | |
* t is the exposure time (“shutter speed”) in seconds | |
*/ | |
double f_number = double.Parse(exif.GetAttribute (ExifInterface.TagAperture)); | |
double shutter_speed = double.Parse(exif.GetAttribute (ExifInterface.TagExposureTime)); | |
double EV = Math.Log ((f_number * f_number) / shutter_speed); | |
// 0 EV = 2.5 lux | |
// (Illuminance) E = 2.5 * 2^EV | |
return 2.5 * Math.Pow(2,EV); | |
} | |
return -1; | |
} | |
void Android.Hardware.Camera.IPictureCallback.OnPictureTaken(byte[] data, Android.Hardware.Camera camera) | |
{ | |
FileOutputStream outStream = null; | |
File dataDir = Android.OS.Environment.ExternalStorageDirectory; | |
if (data != null) { | |
try{ | |
PICTURE_FILENAME = Utils.CurrentTimeMillis() + ".jpg"; | |
outStream = new FileOutputStream(dataDir + "/" + PICTURE_FILENAME); | |
outStream.Write(data); | |
outStream.Close(); | |
}catch(FileNotFoundException e){ | |
System.Console.Out.WriteLine (e.Message); | |
}catch(IOException ie){ | |
System.Console.Out.WriteLine (ie.Message); | |
} | |
} | |
} | |
void Android.Hardware.Camera.IPreviewCallback.OnPreviewFrame(byte[] b, Android.Hardware.Camera c) | |
{ | |
} | |
} | |
} | |
// HOW TO USE | |
LightMeter cSensor; | |
protected override void OnCreate (Bundle savedInstanceState) | |
{ | |
base.OnCreate (savedInstanceState); | |
cSensor = new LightMeter (); | |
} | |
protected override void OnResume () | |
{ | |
base.OnResume (); | |
cSensor.Start(); | |
// after start the sensor you have two methods: | |
// cSensor.TakePicture() take a picture with the front camera to be used as source for ExifScan | |
// cSensor.GetLux() get Lux (illuminance) value | |
} | |
protected override void OnPause () | |
{ | |
base.OnPause (); | |
cSensor.Stop(); | |
} | |
// Utils class | |
using System; | |
namespace YourNamespace | |
{ | |
public class Utils | |
{ | |
public static long CurrentTimeMillis(){ | |
return (long)(DateTime.Now - new DateTime (1970, 1, 1)).TotalMilliseconds; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment