Calling IKScannerDeviceView from Qt

I have a Qt application on MacOS written in C++ and I want to access a scanner. I found the Mac frameworks ImageCaptureCore for scanner access without GUI and ImageKit with GUI. I looked at several code examples, I looked a little bit into Objective-C and finally I got the non-GUI functions to work. But the GUI just never shows up. I created an IKScannerDeviceView object and fed it into a QMacCocoaViewContainer in order to display it in the Qt app. The container window shows up but it is empty. I tested the QMacCocoaViewContainer with a NSTextView object and this works very well. Both NSTextView and IKScannerDeviceView are derived from NSView.

So it might as well be a problem on the scanner side. You have to create a ICDeviceBrowser and wait for the didAddDevice event showing your scanner. This is working. Then you select the scanner into the IKScannerDeviceView with setScannerDevice and wait for deviceDidBecomeReady. This is never happening. Again it's the IKScannerDeviceView which is just not reacting.

What can I do to make IKScannerDeviceView work?

Qt 5.9.7, OS X El Capitan 10.11.6, Scanner: "Canon TS5100 series" working fine in the "Image Capture" app of MacOS.

I attach the code for a minimal test application.

myMacScanner.h:

#ifndef MYMACSCANNER_H
#define MYMACSCANNER_H

#include <QObject>
#include <QString>
class QMacCocoaViewContainer;

class myMacScanner : public QObject
  {
  Q_OBJECT
public:
  myMacScanner(QObject *parent) : QObject(parent) { }
  void start(QWidget *parentWidget, QString scannerName);
  QMacCocoaViewContainer *m_devViewContainer;
signals:
  void si_scanned(); // todo
  };

#endif // MYMACSCANNER_H

myMacScanner.cpp:

#include <Cocoa/Cocoa.h>
#include <Quartz/Quartz.h>
#include <ImageCaptureCore/ImageCaptureCore.h>
#include <QMacCocoaViewContainer>
#include "myMacScanner.h"

// code examples:
// https://stackru.com/questions/12326156/how-to-use-ikscannerdeviceview-in-cocoa
// https://stackru.com/questions/38973881/swift-scanning-with-ikscannerdeviceview-on-osx
// https://ios.developreference.com/article/21675240/IKScannerDeviceView+is+only+working+once
// https://www.purebasic.fr/english/viewtopic.php?f=19&t=61978

QString qt_mac_NSStringToQString(const NSString *nsstr)
  {
  NSRange range;
  range.location = 0;
  range.length = [nsstr length];
  QString result(range.length, QChar(0));

  unichar *chars = new unichar[range.length];
  [nsstr getCharacters:chars range:range];
  result = QString::fromUtf16(chars, range.length);
  delete[] chars;
  return result;
  }


@interface myMacScannerDelegate : NSObject <IKScannerDeviceViewDelegate, ICScannerDeviceDelegate, ICDeviceBrowserDelegate>
  {
  myMacScanner *m_myMacSc;
  IKScannerDeviceView*m_devView;
  QString m_devName;
  }
// ___________________________
// IKScannerDeviceViewDelegate
- (void)useMyMacScanner:(myMacScanner *)sc;
- (void)scannerDeviceView:(IKScannerDeviceView*)scannerDeviceView didScanToURL:(NSURL *)url fileData:(NSData *)data error:(NSError *)error;
- (void)scannerDeviceView:(IKScannerDeviceView*)scannerDeviceView didEncounterError: (NSError *)error;
// ___________________________
// ICScannerDeviceDelegate
- (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner;
- (void)scannerDevice:(ICScannerDevice *)scanner didCompleteOverviewScanWithError:(NSError *)error;
- (void)device:(ICDevice *)device didOpenSessionWithError:(NSError *)error;
- (void)didRemoveDevice:(ICDevice *)device;
- (void)deviceDidBecomeReady:(ICDevice *)device;
// ___________________________
// ICDeviceBrowserDelegate
- (void)setDevView:(IKScannerDeviceView *)devView;
- (void)setDevName:(QString)devName;
- (void)deviceBrowser:(ICDeviceBrowser*)browser didAddDevice:(ICDevice*)device moreComing:(BOOL)moreComing;
@end

@implementation myMacScannerDelegate
// ___________________________
// IKScannerDeviceViewDelegate
- (void)useMyMacScanner:(myMacScanner *)sc { m_myMacSc=sc; }
- (void)scannerDeviceView:(IKScannerDeviceView *)scannerDeviceView didScanToURL:(NSURL *)url fileData:(NSData *)data error:(NSError *)error
  {  // will be called for file or memory based transfer. For memory based transfer NSData will contain the 'final' scanned data as a TIFF image.
  if(m_myMacSc)
    emit m_myMacSc->si_scanned();  // todo
  };
/*
- (void)scannerDeviceView: (IKScannerDeviceView *)scannerDeviceView didScanToBandData: (ICScannerBandData*)data scanInfo: (NSDictionary*)scanInfo error: (NSError *)error
  { // will be called for each image band that gets scanned in memory based mode.
    // The 'data' parameter describes the scanned image data. Note that rotation/cropping/image adjustments
    // are not applied yet. The 'scanInfo' parameter contains additional information (rotation angle, ...)
    // that should be applied once the scan is completed.
  }*/
- (void)scannerDeviceView: (IKScannerDeviceView *)scannerDeviceView didEncounterError: (NSError *)error
  { // This message is sent every time the scanner device reports an error.
  qDebug("IKScannerDeviceViewDelegate:.didEncounterError");
  }
// ___________________________
// ICScannerDeviceDelegate
- (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner
  {
  qDebug("ICScannerDeviceDelegate::scannerDeviceDidBecomeAvailable");
  [scanner requestOpenSession];
  }
- (void)scannerDevice:(ICScannerDevice*)scanner didCompleteOverviewScanWithError:(NSError *)error
  {
  qDebug("ICScannerDeviceDelegate::didCompleteOverviewScanWithError");
  }
- (void)device:(ICDevice*)device didOpenSessionWithError:(NSError *)error
  {
  qDebug("ICScannerDeviceDelegate::didOpenSessionWithError %1i",(int)error.code);
  }
- (void)didRemoveDevice:(ICDevice*)device
  {
  qDebug("ICScannerDeviceDelegate::didRemoveDevice");
  }
- (void)deviceDidBecomeReady:(ICDevice*)device
  {
  qDebug("ICScannerDeviceDelegate::deviceDidBecomeReady");
  ICScannerDevice *scanner=(ICScannerDevice*)device;
  [scanner requestOverviewScan];
  }
// ___________________________
// ICDeviceBrowserDelegate
- (void)setDevView:(IKScannerDeviceView *)devView { m_devView = devView; }
- (void)setDevName:(QString)devName { m_devName=devName; }
- (void)deviceBrowser:(ICDeviceBrowser*)browser didAddDevice:(ICDevice*)device moreComing:(BOOL)moreComing
    {
    qDebug("ICDeviceBrowserDelegate::didAddDevice");
    if ( (device.type & ICDeviceTypeMaskScanner) == ICDeviceTypeScanner )
      {
      QString name = qt_mac_NSStringToQString(device.name);
      if(m_devName==name)
        {
        ICScannerDevice *scanner=(ICScannerDevice*)device;
        scanner.delegate = self;
        scanner.transferMode = ICScannerTransferModeMemoryBased;
        qDebug("ICDeviceBrowserDelegate::didAddDevice: %s, moreComing=%1i",name.toUtf8().data(),moreComing);
        [m_devView setScannerDevice:scanner];
        //[scanner requestOpenSession];
        //[scanner requestOverviewScan];
        }
      }
    };
- (void)deviceBrowser:(ICDeviceBrowser*)browser didRemoveDevice:(ICDevice*)device moreGoing:(BOOL)moreGoing
  {
  qDebug("ICDeviceBrowserDelegate::didRemoveDevice");
  [device requestCloseSession];
  }
@end

void myMacScanner::start(QWidget *parentWidget, QString scannerName)
  {
  myMacScannerDelegate *deleg = [[myMacScannerDelegate alloc] init];
  [deleg useMyMacScanner:this];

  IKScannerDeviceView*devView = [IKScannerDeviceView alloc];
  devView.transferMode = IKScannerDeviceViewTransferModeMemoryBased;
  devView.delegate = deleg;
  devView.mode = IKScannerDeviceViewDisplayModeAdvanced;
  [devView initWithFrame : NSMakeRect(0, 0, 300, 300)];
  m_devViewContainer = new QMacCocoaViewContainer(0,parentWidget);
#if 0  // test QMacCocoaViewContainer with NSTextView
  NSTextView *text = [[NSTextView alloc] initWithFrame : NSMakeRect(0, 0, 300, 300)];
  m_devViewContainer->setCocoaView(text);
#else
  m_devViewContainer->setCocoaView(devView);
#endif
  m_devViewContainer->show();

  [deleg setDevName:scannerName];
  [deleg setDevView:devView];
  ICDeviceBrowser *browser = [[ICDeviceBrowser alloc] init];
  browser.delegate = deleg;
  browser.browsedDeviceTypeMask = (ICDeviceTypeMask)(ICDeviceLocationTypeMaskLocal|ICDeviceLocationTypeMaskRemote|ICDeviceTypeMaskScanner|ICDeviceTypeCamera);
  [browser start];
  }

testMacScanner.cpp:

#include <QApplication>
#include "myMacScanner.h"

int main(int argc, char *argv[])
  {
  QApplication a(argc, argv);
  myMacScanner *m_macScanner=new myMacScanner(&a);
  m_macScanner->start(NULL,"Canon TS5100 series");
  return a.exec();
  }

testMacScanner.pro:

QT       += core gui widgets
TARGET = testMacScanner
TEMPLATE = app
LIBS += -framework Foundation
LIBS += -framework ImageCaptureCore
LIBS += -framework Quartz  # for ImageKit
LIBS += -framework AppKit  # for NSTextView, for testing
QMAKE_CXXFLAGS_WARN_ON = -Wno-unused-parameter -Wno-unused-value
CONFIG += c++11
SOURCES += testMacScanner.cpp \    # main
           myMacScanner.mm
HEADERS += myMacScanner.h

My debug output is:

ICDeviceBrowserDelegate::didAddDevice
ICDeviceBrowserDelegate::didAddDevice: Canon TS5100 series, moreComing=0

0 ответов

Другие вопросы по тегам