I want scan many images toghether in c# code, I use twain 3.0.0.
I want to change transfer mode in twain to save my images directly and don't collect these in RAM.
btnstart:
TwainSession _twain;
if (_twain.State == 4)
{
_stopScan = false;
if (_twain.CurrentSource.Capabilities.CapUIControllable.IsSupported)
{
// hide scanner ui if possible
if (_twain.CurrentSource.Enable(SourceEnableMode.NoUI, false, this.Handle) == ReturnCode.Success)
{
btnStopScan.Enabled = true;
btnStartCapture.Enabled = false;
}
}
}
data transfer:
_twain.DataTransferred += (s, e) =>
{
PlatformInfo.Current.Log.Info("Transferred data event on thread " + Thread.CurrentThread.ManagedThreadId);
// example on getting ext image info
var infos = e.GetExtImageInfo(NTwain.Data.ExtendedImageInfo.Camera).Where(it => it.ReturnCode == ReturnCode.Success);
foreach (var it in infos)
{
var values = it.ReadValues();
PlatformInfo.Current.Log.Info(string.Format("{0} = {1}", it.InfoID, values.FirstOrDefault()));
break;
}
Image img = null;
if (e.NativeData != IntPtr.Zero)
{
var stream = e.GetNativeImageStream();
if (stream != null)
{
img = Image.FromStream(stream);
}
}
else if (!string.IsNullOrEmpty(e.FileDataPath))
{
img = new Bitmap(e.FileDataPath);
}
}
Related
It would appear that something has changed in recent versions of iOS as it relates to saving GPS data in photos and subsequent to a bug in the Xam.Plugin.Media library, I am attempting to figure out how to take a photo and save it to the Photo Gallery with intact GPS data using iOS 13.4.1 and Xamarin.iOS 13.16.0.13. I have looked at the internals of Xam.Plugin.Media and using this as a starting point, tried to cobble something together on the hunch that because Xam.Plugin.Media uses ALAssetsLibrary to save to the Photo Gallery, perhaps this was why the GPS data is not being saved with the photo.
I am currently at the point where I had thought I would be able to take the photo, merge GPS data into the file and save the JPG output to a temporary location in the app folder (i.e. I haven't even gotten to saving the photo to the gallery yet). But when I examine this temp file using either the Preview app on MacOS or Photoshop to view the GPS metadata, the data is not there.
My handler for UIImagePickerController.FinishedPickingMedia is this:
private void OnFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs e)
{
try
{
NSDictionary info = e.Info;
NSDictionary meta = null;
UIImage image = null;
string savedImagePath = null;
if (_imagePicker.SourceType == UIImagePickerControllerSourceType.Camera)
{
meta = (NSDictionary)info[UIImagePickerController.MediaMetadata];
image = (UIImage)info[UIImagePickerController.OriginalImage];
if (meta != null && meta.ContainsKey(ImageIO.CGImageProperties.Orientation))
{
var newMeta = new NSMutableDictionary();
newMeta.SetValuesForKeysWithDictionary(meta);
var newTiffDict = new NSMutableDictionary();
newTiffDict.SetValuesForKeysWithDictionary(meta[ImageIO.CGImageProperties.TIFFDictionary] as NSDictionary);
newTiffDict.SetValueForKey(meta[ImageIO.CGImageProperties.Orientation], ImageIO.CGImageProperties.TIFFOrientation);
newMeta[ImageIO.CGImageProperties.TIFFDictionary] = newTiffDict;
meta = newMeta;
}
if (_locationPermissionGranted)
{
meta = SetGpsLocation(meta);
}
savedImagePath = SaveImageWithMetadata(image, meta);
}
string aPath = null;
if (_imagePicker.SourceType != UIImagePickerControllerSourceType.Camera)
{
// Try to get the album path's URL.
var url = (NSUrl)info[UIImagePickerController.ReferenceUrl];
aPath = url?.AbsoluteString;
}
}
catch (Exception ex)
{
Console.WriteLine($"Unable to get metadata: {ex}");
}
}
Which calls:
private NSDictionary SetGpsLocation(NSDictionary meta)
{
var newMeta = new NSMutableDictionary();
newMeta.SetValuesForKeysWithDictionary(meta);
var newGpsDict = new NSMutableDictionary();
newGpsDict.SetValueForKey(new NSNumber(Math.Abs(_lat)), ImageIO.CGImageProperties.GPSLatitude);
newGpsDict.SetValueForKey(new NSString(_lat > 0 ? "N" : "S"), ImageIO.CGImageProperties.GPSLatitudeRef);
newGpsDict.SetValueForKey(new NSNumber(Math.Abs(_long)), ImageIO.CGImageProperties.GPSLongitude);
newGpsDict.SetValueForKey(new NSString(_long > 0 ? "E" : "W"), ImageIO.CGImageProperties.GPSLongitudeRef);
newGpsDict.SetValueForKey(new NSNumber(_altitude), ImageIO.CGImageProperties.GPSAltitude);
newGpsDict.SetValueForKey(new NSNumber(0), ImageIO.CGImageProperties.GPSAltitudeRef);
newGpsDict.SetValueForKey(new NSNumber(_speed), ImageIO.CGImageProperties.GPSSpeed);
newGpsDict.SetValueForKey(new NSString("K"), ImageIO.CGImageProperties.GPSSpeedRef);
newGpsDict.SetValueForKey(new NSNumber(_direction), ImageIO.CGImageProperties.GPSImgDirection);
newGpsDict.SetValueForKey(new NSString("T"), ImageIO.CGImageProperties.GPSImgDirectionRef);
newGpsDict.SetValueForKey(new NSString(_timestamp.ToString("hh:mm:ss")), ImageIO.CGImageProperties.GPSTimeStamp);
newGpsDict.SetValueForKey(new NSString(_timestamp.ToString("yyyy:MM:dd")), ImageIO.CGImageProperties.GPSDateStamp);
newMeta[ImageIO.CGImageProperties.GPSDictionary] = newGpsDict;
return newMeta;
}
private string SaveImageWithMetadata(UIImage image, NSDictionary meta)
{
string outputPath = null;
try
{
var finalQuality = 1.0f;
var imageData = image.AsJPEG(finalQuality);
// Continue to move down quality, rare instances.
while (imageData == null && finalQuality > 0)
{
finalQuality -= 0.05f;
imageData = image.AsJPEG(finalQuality);
}
if (imageData == null)
{
throw new NullReferenceException("Unable to convert image to jpeg, please ensure file exists or " +
"lower quality level");
}
var dataProvider = new CGDataProvider(imageData);
var cgImageFromJpeg = CGImage.FromJPEG(dataProvider, null, false, CGColorRenderingIntent.Default);
var imageWithExif = new NSMutableData();
var destination = CGImageDestination.Create(imageWithExif, UTType.JPEG, 1);
var cgImageMetadata = new CGMutableImageMetadata();
var destinationOptions = new CGImageDestinationOptions();
if (meta.ContainsKey(ImageIO.CGImageProperties.Orientation))
{
destinationOptions.Dictionary[ImageIO.CGImageProperties.Orientation] =
meta[ImageIO.CGImageProperties.Orientation];
}
if (meta.ContainsKey(ImageIO.CGImageProperties.DPIWidth))
{
destinationOptions.Dictionary[ImageIO.CGImageProperties.DPIWidth] =
meta[ImageIO.CGImageProperties.DPIWidth];
}
if (meta.ContainsKey(ImageIO.CGImageProperties.DPIHeight))
{
destinationOptions.Dictionary[ImageIO.CGImageProperties.DPIHeight] =
meta[ImageIO.CGImageProperties.DPIHeight];
}
if (meta.ContainsKey(ImageIO.CGImageProperties.ExifDictionary))
{
destinationOptions.ExifDictionary =
new CGImagePropertiesExif(meta[ImageIO.CGImageProperties.ExifDictionary] as NSDictionary);
}
if (meta.ContainsKey(ImageIO.CGImageProperties.TIFFDictionary))
{
destinationOptions.TiffDictionary =
new CGImagePropertiesTiff(meta[ImageIO.CGImageProperties.TIFFDictionary] as NSDictionary);
}
if (meta.ContainsKey(ImageIO.CGImageProperties.GPSDictionary))
{
destinationOptions.GpsDictionary =
new CGImagePropertiesGps(meta[ImageIO.CGImageProperties.GPSDictionary] as NSDictionary);
}
if (meta.ContainsKey(ImageIO.CGImageProperties.JFIFDictionary))
{
destinationOptions.JfifDictionary =
new CGImagePropertiesJfif(meta[ImageIO.CGImageProperties.JFIFDictionary] as NSDictionary);
}
if (meta.ContainsKey(ImageIO.CGImageProperties.IPTCDictionary))
{
destinationOptions.IptcDictionary =
new CGImagePropertiesIptc(meta[ImageIO.CGImageProperties.IPTCDictionary] as NSDictionary);
}
destination.AddImageAndMetadata(cgImageFromJpeg, cgImageMetadata, destinationOptions);
var success = destination.Close();
if (success)
{
outputPath = GetOutputPath();
imageWithExif.Save(outputPath, true);
}
}
catch (Exception e)
{
Console.WriteLine($"Unable to save image with metadata: {e}");
}
return outputPath;
}
private static string GetOutputPath()
{
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "temp");
Directory.CreateDirectory(path);
var timestamp = DateTime.UtcNow.ToString("yyyMMdd_HHmmss", CultureInfo.InvariantCulture);
var name = "IMG_" + timestamp + ".jpg";
return Path.Combine(path, GetUniquePath(path, name));
}
private static string GetUniquePath(string path, string name)
{
var ext = Path.GetExtension(name);
name = Path.GetFileNameWithoutExtension(name);
var fullName = name + ext;
var i = 1;
while (File.Exists(Path.Combine(path, fullName)))
{
fullName = name + "_" + (i++) + ext;
}
return Path.Combine(path, fullName);
}
The file is saved successfully, but without the expected GPS metadata. Which leads me to believe that the problem may be to do with the way I am saving the temporary photo or saving the GPS metadata to it in either SaveImageWithMetadata or SetGpsLocation.
If anyone can provide some info on what actually works now with iOS 13.4.1 and saving GPS data to photos, I would be very appreciative.
I have been developing a game in Unity3D in C#. So I have set the game to upload the game save file
to Parse every 2 minutes. When I run the code in Unity it works fine, it saves the game save file locally, and every 2 minutes it uploads it to Parse, it also points to the user who's playing the game. Although when I run the game on a mobile device the file does not upload, I have been refreshing my parse data object in the last half an hour and I still haven't got anything.
Here is the code:
void Start ()
{
if (ParseUser.CurrentUser != null)
{
gapTest = true;
}
}
void Update ()
{
if(gapTest)
{
StartCoroutine(UploadFile());
}
if (uploadSaveFile)
{
OnZipComplete();
uploadSaveFile = false;
}
else if (createNewSaveFile)
{
CreateNewSaveFile();
createNewSaveFile = false;
}
}
IEnumerator UploadFile()
{
gapTest = false;
yield return new WaitForSeconds (120.0F);
if(ParseUser.CurrentUser != null)
{
OnZipComplete();
}
gapTest = true;
}
void OnZipComplete()
{
var query = ParseObject.GetQuery("GameSave").WhereEqualTo("UserObjectId", ParseUser.CurrentUser);
if (existingGameSave == null)
{
query.FindAsync().ContinueWith(t =>
{
IEnumerable<ParseObject> results = t.Result;
int resultCount = 0;
foreach (var result in results)
{
if (resultCount > 0)
{
Debug.LogError("Found more than one save file for user!");
}
else
{
resultCount++;
existingGameSave = result;
uploadSaveFile = true;
}
}
if (resultCount == 0)
{
createNewSaveFile = true;
}
});
}
else
{
UpdateExistingSaveFile();
}
}
private void CreateNewSaveFile()
{
//upload the file to parse
zipPath = Application.persistentDataPath + "/SaveGame.zip";
byte[] data = System.Text.Encoding.UTF8.GetBytes(zipPath);
ParseFile GameSave = new ParseFile("GameSave.zip", data);
var gameSave = new ParseObject("GameSave");
gameSave["UserObjectId"] = ParseUser.CurrentUser;
gameSave["GameSaveFile"] = GameSave;
Task saveTask = gameSave.SaveAsync();
Debug.Log("New Game save file has been uploaded");
}
void UpdateExistingSaveFile()
{
//upload the file to parse
UserIdFile = Application.persistentDataPath + "/UserId.txt";
zipPath = Application.persistentDataPath + "/SaveGame.zip";
byte[] data = System.Text.Encoding.UTF8.GetBytes(zipPath);
ParseFile GameSave = new ParseFile("GameSave.zip", data);
existingGameSave["GameSaveFile"] = GameSave;
Task saveTask = existingGameSave.SaveAsync();
Debug.Log("Existing Game save file has been uploaded");
}
This might be a problem related to permission on android device.
Go to Build Setting > Player Setting > Other Settings, and check "Write Access", by default, it is internal Only which means that the path is for development purpose only.
Try Setting the Write Access as External(SD Card) or add WRITE_ EXTERNAL_STORAGE permission into AndroidManifest.xml. And check Android/file/com.your.appid/files of your sd card if your data is actually getting written on device.
If data is getting written, then it will sure get uploaded on parse.com.
I have a problem with scanning with WIA.
public List<Image> Scan(string scannerId)
{
var images = new List<Image>();
var hasMorePages = true;
while (hasMorePages)
{
// select the correct scanner using the provided scannerId parameter
var manager = new DeviceManager();
Device device = null;
foreach (DeviceInfo info in manager.DeviceInfos)
{
if (info.DeviceID == scannerId)
{
// connect to scanner
device = info.Connect();
break;
}
}
// device was not found
if (device == null)
{
// enumerate available devices
string availableDevices = "";
foreach (DeviceInfo info in manager.DeviceInfos)
{
availableDevices += info.DeviceID + "n";
}
// show error with available devices
throw new Exception("The device with provided ID could not be found. Available Devices:n" +
availableDevices);
}
Item item = device.Items[1];
try
{
// scan image
ICommonDialog wiaCommonDialog = new CommonDialog();
var image = (ImageFile) wiaCommonDialog.ShowTransfer(item, WiaFormatBmp, true); // <--- exception goes from there
// save to temp file
string fileName = "test.bmp";//Path.GetTempFileName();
File.Delete(fileName);
image.SaveFile(fileName);
image = null;
// add file to output list
images.Add(Image.FromFile(fileName));
}
catch (Exception exc)
{
throw exc;
}
finally
{
item = null;
//determine if there are any more pages waiting
Property documentHandlingSelect = null;
Property documentHandlingStatus = null;
foreach (Property prop in device.Properties)
{
if (prop.PropertyID == WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_SELECT)
documentHandlingSelect = prop;
if (prop.PropertyID == WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_STATUS)
documentHandlingStatus = prop;
}
// assume there are no more pages
hasMorePages = false;
// may not exist on flatbed scanner but required for feeder
if (documentHandlingSelect != null)
{
// check for document feeder
if ((Convert.ToUInt32(documentHandlingSelect.get_Value()) && WIA_DPS_DOCUMENT_HANDLING_SELECT.FEEDER) != 0)
{
hasMorePages = ((Convert.ToUInt32(documentHandlingStatus.get_Value()) &&
WIA_DPS_DOCUMENT_HANDLING_STATUS.FEED_READY) != 0);
}
}
}
}
return images;
}
When the scanning is completed i get an exception: "Dynamic operations can only be performed in homogenous AppDomain.". Can someone explain me what im doing wrong? I tried to use it in another Thread but still get the same exception.
Scanner: DSmobile 700D.
If the filename contains # - download from skydrive fails. More precisely - length of result always 0. Other files are loaded without any problems;
Thanks
start downloading:
if (!loading) {
if (!Storage.Exists(item.Name)
|| MessageBox.Show(AppResources.alreadyExists, AppResources.confirmation, MessageBoxButton.OKCancel) == MessageBoxResult.OK) {
loading = true;
App.loadInfo.Name = item.Name;
App.loadInfo.Info = AppResources.loadingStart;
PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disa bled;
client.DownloadAsync(item.Id + CONTENT, item);
}
}
download completed:
void client_DownloadCompleted(object sender, LiveDownloadCompletedEventArgs e) {
PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Enabled;
try {
FileItem item = e.UserState as FileItem;
if (e.Error == null
&& !e.Cancelled
&& e.UserState != null
&& item.Size == e.Result.Length.ToString()) //LENGTH = 0 { Storage.SaveFile(item.Name, e.Result);
App.loadInfo.Info = AppResources.loadingComplete;
new GetIcon(item._name);
}
else {
if (item != null) App.loadInfo.Name = item.Name;
App.loadInfo.Info = AppResources.loadingError;
}
}
finally { App.loadInfo.Progress = 0; loading = false; MakeUi(); }
}
LiveDownloadProgressChangedEventArgs does not arise
If this is genuinely the case, can you not just strip the fragments from the URI before you make the request?
Live Connect & Live SDK Known Issues
I am using Watin to copy a image to the clipboard, I am getting this error when I do so,
is there a work around to this using AlertDialogHandler?
public System.Drawing.Image GetPicture(WatiN.Core.Image image, ref IE browser)
{
if (image == null || !image.Exists || string.IsNullOrEmpty(image.Src))
return null;
const string t_js =
#"var div = document.images[{0}];
div.contentEditable ='true';
var controlRange;
if(document.body.createControlRange)
{{
controlRange = document.body.createControlRange();
controlRange.addElement(div);
controlRange.execCommand('Copy');
}}
div.contentEditable = 'false';";
var cnt = -1;
foreach (var image1 in browser.Images)
{
cnt++;
if (image1 != null && image1.Exists && !string.IsNullOrEmpty(image1.Src) && image1.Src.ToLower() == image.Src.ToLower())
break;
}
var script = string.Format(t_js, cnt);
WatiN.Core.DialogHandlers.AlertDialogHandler alertDialogHandler = new WatiN.Core.DialogHandlers.AlertDialogHandler ();
using (new WatiN.Core.DialogHandlers.UseDialogOnce(browser.DialogWatcher, alertDialogHandler ))
{
browser.RunScript(script); // Exception comes here !!
alertDialogHandler.WaitUntilExists();
alertDialogHandler.OKButton.Click();
browser.WaitForComplete();
}
var data = Clipboard.GetDataObject();
if (data == null)
return null;
var q = data.GetFormats();
q.ToString();
var q2 = data.GetFormats(true);
q2.ToString();
if (data.GetDataPresent(DataFormats.Bitmap))
{
var img = data.GetData(DataFormats.Bitmap, true);
return img as System.Drawing.Image;
}
if (data.GetDataPresent(DataFormats.Dib))
{
var img = data.GetData(DataFormats.Dib, true);
return img as System.Drawing.Image;
}
if (data.GetDataPresent(DataFormats.EnhancedMetafile))
{
var img = data.GetData(DataFormats.EnhancedMetafile, true);
return img as System.Drawing.Image;
}
if (data.GetDataPresent(DataFormats.MetafilePict))
{
var img = data.GetData(DataFormats.MetafilePict, true);
return img as System.Drawing.Image;
}
if (data.GetDataPresent(DataFormats.Tiff))
{
var img = data.GetData(DataFormats.Tiff, true);
return img as System.Drawing.Image;
}
if (data.GetDataPresent(DataFormats.Serializable))
{
var img = data.GetData(DataFormats.Serializable, true);
return img as System.Drawing.Image;
}
return null;
}
Thanks!
image of the security exception:
I believe it has to do something with IE Security settings
Goto
Security Tab -> Select proper zone (Internet/Local/etc) -> Click on Custome Level button -> Enable (Scripting - > Allow programmatic clipboard access)