WIA + network scanner with adf = 1 page - wia

I am writing a program to work with a network scanner through WIA.
Everything works fine when scanning only one page. When I turn on the feeder:
foreach (WIA.Property deviceProperty in wia.Properties)
{
if (deviceProperty.Name == "Document Handling Select")
{
int value = duplex ? 0x004 : 0x001;
deviceProperty.set_Value(value);
}
}
the program receives a scan, the signal that there are still documents in the feeder and falls off with com error (scanner continues to scan).
Here's the code check the pages in the feeder:
//determine if there are any more pages waiting
Property documentHandlingSelect = null;
Property documentHandlingStatus = null;
foreach (Property prop in wia.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;
}
if ((Convert.ToUInt32(documentHandlingSelect.get_Value()) & 0x00000001) != 0)
{
return ((Convert.ToUInt32(documentHandlingStatus.get_Value()) & 0x00000001) != 0);
}
return false;
Getting the picture code:
imgFile = (ImageFile)WiaCommonDialog.ShowTransfer(item, wiaFormatJPEG, false);
Unfortunately could not find an example of using WIA WSD. Perhaps there are some settings to get multiple images through WSD.

I had almost the same problem using WIA 2.0 with vba to control a Brother MFC-5895CW Multi-Function Scanner.
When I transferred scans from the ADF I was not capable to catch more than 2 pictures to image-objects (and I tried probably every existing option and worked days and hours on that problem!)
The only solution I found with that scanner was to use the ShowAcquisitionWizard-method of the WIA.CommonDialog-Object to batch-transfer all scanned files to a specified folder. It was more a workaround than a satisfying solution for me because the postprocessing would have become more complicated.
Surprise surprise, I tried the same procedure on the neat-scanner of my client... ShowAcquisitionWizard delivered only one scanned page to the specified folder, the other pages disappeared.
To my second surprise with the 'CommonDialog.ShowTransfer'-method I was able to transfer all scanned documents picture by picture into image-objects in my application.

Related

How to have custom video media/stream sink request RGB32 frames in media foundation?

I am trying to make a custom media sink for video playback in an OpenGL application (without the various WGL_NV_DX_INTEROP, as I am not sure if all my target devices support this).
What I have done so far is to write a custom stream sink that accepts RGB32 samples and set up playback with a media session, however i encountered a problem with initial testing of playing an mp4 file:
one (or more) of the MFTs in the generated topology keep failing with an error code MF_E_TRANSFORM_NEED_MORE_INPUT, therefore my stream sink never receives samples
After a few samples have been requested, the media session receives the event MF_E_ATTRIBUTENOTFOUND, but I still don't know where it is coming from
If, however, I configure the stream sink to receive NV12 samples, everything seems to work fine.
My best guess is the color converter MFT generated by the TopologyLoader needs some more configuration, but I don't know how to do that, considering that I need to keep this entire process indipendent from the original file types.
I've made a minimal test case, that demonstrate the use of a custom video renderer with a classical Media Session.
I use big_buck_bunny_720p_50mb.mp4, and i don't see any problems using RGB32 format.
Sample code here : https://github.com/mofo7777/Stackoverflow under MinimalSinkRenderer.
EDIT
Your program works well with big_buck_bunny_720p_50mb.mp4. I think that your mp4 file is the problem. Share it, if you can.
I just made a few changes :
You Stop on MESessionEnded, and you Close on MESessionStopped.
case MediaEventType.MESessionEnded:
Debug.WriteLine("MediaSession:SesssionEndedEvent");
hr = mediaSession.Stop();
break;
case MediaEventType.MESessionClosed:
Debug.WriteLine("MediaSession:SessionClosedEvent");
receiveSessionEvent = false;
break;
case MediaEventType.MESessionStopped:
Debug.WriteLine("MediaSession:SesssionStoppedEvent");
hr = mediaSession.Close();
break;
default:
Debug.WriteLine("MediaSession:Event: " + eventType);
break;
Adding this to wait for the sound, and to check sample is ok :
internal HResult ProcessSample(IMFSample s)
{
//Debug.WriteLine("Received sample!");
CurrentFrame++;
if (s != null)
{
long llSampleTime = 0;
HResult hr = s.GetSampleTime(out llSampleTime);
if (hr == HResult.S_OK && ((CurrentFrame % 50) == 0))
{
TimeSpan ts = TimeSpan.FromMilliseconds(llSampleTime / (10000000 / 1000));
Debug.WriteLine("Frame {0} : {1}", CurrentFrame.ToString(), ts.ToString());
}
// Do not call SafeRelease here, it is done by the caller, it is a parameter
//SafeRelease(s);
}
System.Threading.Thread.Sleep(26);
return HResult.S_OK;
}
In
public HResult SetPresentationClock(IMFPresentationClock pPresentationClock)
adding
SafeRelease(PresentationClock);
before
if (pPresentationClock != null)
PresentationClock = pPresentationClock;

MultiRoute Audio Input in iOS

We've been working with AudioUnits in Core Audio. It is simultaniously a very powerful audio framework, and one of the worst documented which makes it both a joy and a frustration to work with.
We want to accomplish something we know iPads had been able to do since iOS 6.0 - Multiple audio inputs.
So far - from the 2012 Developer Talk - It appears you have to set the audio session to MultiRoute. We've done this. If I plug in an a soundcard from a keyboard. I can see that there are two inputs. Great. We're then told that we need to set a ChannelMap on a Remote I/O unit.
To what? Well... here's where it gets vague. We need to set all the channels we don't want to -1 and the channels we want to 0 and 1 (for stereo input or for mono?).
We attempt this and... nothing. Sound still plays through on the 'last in wins' principle. Microphone if everything plugged out, soundcard if that's the one plugged in. But we can't switch between them.
This setup code is always run before the other function listed
func setupAudioSession() {
self.audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSessionCategoryMultiRoute, with: [.mixWithOthers])
try audioSession.setActive(true)
audioSessionWasSetup = true
} catch let error {
//TODO: Implement something here
print(error)
audioSessionWasSetup = false
}
}
We then have a remote I/O with an associated audiograph set up. This has been tested and works beautifully. But we need to be able to set where it's pulling sound from.
I've attempted to do it with this, but not only doesn't it have any effect... nothing happens.
Am I missing something?
private func setChannelMap(onAudioUnit audioUnit: AudioUnit?, toChannel channelIndex: Int = 0) {
var channelMap: [Int32] = []
if audioUnit == nil {
return
}
var numberOfInputChannels: UInt32 = 4 // Two stereo inputs? - I'm just guessing here
let mapSize: UInt32 = numberOfInputChannels * UInt32(MemoryLayout<Int32>.size);
for _ in 0...(numberOfInputChannels) {
channelMap.append(-1)
}
channelMap[2 * channelIndex] = 0;
channelMap[2 * channelIndex + 1] = 1;
let status = AudioUnitSetProperty(audioUnit!,
kAudioOutputUnitProperty_ChannelMap,
kAudioUnitScope_Input,
0,
&channelMap,
mapSize);
self.checkError(status, "Failed to set Channel Map on input unit")
}
There isn't any documentation on this at all as far as I've been able to find. Nor any code examples.
I hope you can help us.

playing PDE files in a loop?

I'm still relatively new to Processing. We are thinking of showing our Processing work in a loop for a small exhibition. Is there a way to play multiple PDEs in a loop? I know I can export as frames and then assemble them as a longer loop-able Quicktime file, but I'm wondering if there's any way to play and loop the files themselves?
Also, for interactive PDEs, what's the best way to present them? We are thinking of having a couple of computers with PDEs running in Processing but it would be nice to have a file run for 20 minutes and then open another file for 20 minutes.
Thanks in advance!
You should be able to put together a shell/batch script that uses the processing-java command line executable.
You should be able to set that up via the Tools > Install "processing-java"
If you're not confortable with bash/batch scripting you could even write a Processing sketch that launches Processing sketches
Here's a very rough take on it using selectFolder() and exec():
final int SKETCH_RUN_TIME = 10000;//10 seconds for each sketch, feel free to change
ArrayList<File> sketches = new ArrayList<File>();
int sketchIndex = 0;
void setup(){
selectFolder("Select a folder containing Processing sketches:", "folderSelected");
}
void draw(){
}
void nextSketch(){
//run sketch
String sketchPath = sketches.get(sketchIndex).getAbsolutePath();
println("launching",sketchPath);
Process sketch = exec("/usr/local/bin/processing-java",
"--sketch="+sketchPath,
"--present");
//increment sketch index for next time around (checking the index is still valid, otherwise go back to 0)
sketchIndex++;
if(sketchIndex >= sketches.size()){
sketchIndex = 0;
}
//delay is deprecated so you shouldn't use this a lot, but as a proof concept this will do
delay(SKETCH_RUN_TIME);
nextSketch();
}
void folderSelected(File selection) {
if (selection == null) {
println("No folder ? Ok, maybe another time. Bye! :)");
exit();
} else {
File[] files = selection.listFiles();
//filter just Processing sketches
for(int i = 0; i < files.length; i++){
if(files[i].isDirectory()){
String folderName = files[i].getName();
File[] sketchFiles = files[i].listFiles();
boolean isValidSketch = false;
//search for a .pde file with the same folder name to check if it's a valid sketch
for(File f : sketchFiles){
if(f.getName().equals(folderName+".pde")){
isValidSketch = true;
break;
}
}
if(isValidSketch) {
sketches.add(files[i]);
}else{
System.out.println(files[i]+" is not a valid Processing sketch");
}
}
}
println("sketches found:",sketches);
nextSketch();
}
}
The code is commented so hopefully it should be easy to read and follow.
You will be prompted to select a folder containing sketches to run.
Note 1: I've used the processing-java path on my machine (/usr/local/bin/processing-java). If you're on Windows this may be different and you need to change this.
Note 2: The processing-java command launches another Process which makes it tricky to close the previous sketch before running the next one. As a workaround for you you could call exit() on each sketch after the amount of time you need.
Note 3: The code will not recursively traverse the selected folder containing sketches, so only the first level sketches will be executed, anything deeper should be ignored.

CreateIconFromResource return NULL and UI crashed after being called thousands of times

Anybody got this problem, anyway I didn't find an answer. The code is simple:
void CbDlg::OnBnClickedOk()
{
for(int i=0; i<1000; i++)
{
HRSRC hRes = ::FindResource(NULL, MAKEINTRESOURCE(IDR_MAINFRAME), RT_GROUP_ICON);
HGLOBAL hResLoad = ::LoadResource(NULL, hRes);
BYTE* pIconBytes = (BYTE*)::LockResource(hResLoad);
int nId = ::LookupIconIdFromDirectory(pIconBytes, TRUE);
hRes = ::FindResource(NULL, MAKEINTRESOURCE(nId), RT_ICON);
DWORD read = ::SizeofResource(NULL ,hRes);
hResLoad = ::LoadResource(NULL, hRes);
pIconBytes = (BYTE*)::LockResource(hResLoad);
if(pIconBytes != NULL)
{
HICON hIcon = ::CreateIconFromResource(pIconBytes, read, TRUE, 0x00030000);
DWORD e = ::GetLastError();
if(hIcon != NULL)
{
::DestroyIcon(hIcon);
}
}
}
}
If I click the Ok button four times (On my computer), CreateIconFromResource start to return NULL (It worked fine before and I could even draw out the icon). As to the GetLastError, it's always return 6 whatever CreateIconFromResource return NULL or not.
When this problem happened, if I drag the title bar to move, UI crashed, see the pictrue.
Of course you can understand this piece of code is just a demo, my real business need to call CreateIconFromResource thousands of times just like this.
UPDATE:
According to Hans' suggestion, I keep tracking the Handles/USER Objects/GDI objects, and found that USER Objects grows 1000 and GDI objects grows 2000 against each clicking to OK button (handles didn't grow), and GDI objects is 9999 when problem happens. But how to release them correctly, when I finish to use? I didn't use that much at one time, but need to load, release, load again, release again... Just like this demo. As MSDN document, I called DestroyIcon for every HICON. What else do I need to do, to finally release the USER/GDI objects?
I found the answer. The success or failure is all due to MSDN.
It says:
"The CreateIconFromResource function calls CreateIconFromResourceEx passing LR_DEFAULTSIZE|LR_SHARED as flags" AND "Do not use this function(DestroyIcon) to destroy a shared icon"
But It also says:
"When you are finished using the icon, destroy it using the DestroyIcon function" in CreateIconFromResource's document.
Actually, the second statement is WRONG.
So, the solution is, using CreateIconFromResourceEx without LR_SHARED, and DestroyIcon every HICON after using.

Geolocator and accuracy in Windows Phone 8

I have a few questions about Geolocator and property DesiredAccuracy.
I have the method GetMyPosition:
public async Task<Geoposition> GetMyPosition()
{
Geoposition myGeoposition = null;
Geolocator myGeolocator = new Geolocator();
myGeolocator.DesiredAccuracy = PositionAccuracy.High;
try
{
myGeoposition = await myGeolocator.GetGeopositionAsync();
return myGeoposition;
}
catch (Exception ex)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("Can't get the position");
});
return null;
}
}
1) Why
Geolocator.DesiredAccuracy = PositionAccuracy.High;
Geolocator.GetGeopositionAsync();
always return Geoposition.Coordinate.PositionSource = Cellular with accuracy 400 - 1600 m (on device Nokia Lumia 520)?
2) Under what settings I can get a high accuracy (50 - 100 m) and PositionSource = Satellite?
3) If I have the loaded maps on my device and I activated the airplane mode on the device, then code
Geolocator myGeolocator = new Geolocator();
myGeolocator.DesiredAccuracy = PositionAccuracy.High;
try
{
myGeoposition = await myGeolocator.GetGeopositionAsync();
return myGeoposition;
}
will work? Without a celluar, only a satellite?
4) How strong is the precision of coordinates depends on the device?
Thanks in advance!
Taken from MSDN
Although the Location Service uses multiple sources of location information, and any of the sources may not be available at any given time (for example, no GPS satellites or cell phone towers may be accessible), the native code layer handles the work of evaluating the available data and choosing the best set of sources. All your application needs to do is to choose between high accuracy or the default, power-optimized setting. You can set this value when you initialize the main Location Service class, GeoCoordinateWatcher.
C#
GeoCoordinateWatcher watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
So it seems like you can't control which source is used but rather the available source will be used based on the specified position accuracy on GeoCoordinateWatcher. Try initializing a GeoCoordinateWatcher with high accuracy and see what happens
var geoWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
You can use
Geolocator myGeolocator = new Geolocator();
myGeolocator.DesiredAccuracyInMeters = 20;
...
to explicitly state how accurate you want the location to be which would allow the device to manage its power a little better but whether you get close to that accuracy with your result depends on the quality of the location the device can get. If you're inside a building for example you're not going to get something that accurate without connecting to WIFI

Resources