Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(203)

Side by Side Diff: chrome/browser/extensions/api/document_scan/document_scan_api.cc

Issue 286933006: Implement a JavaScript API for document scanning (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: API fully up to data (and functional) with respect to API submission, minus image selection API whi… Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/api/document_scan/document_scan_api.h"
6
7 #include <algorithm>
8
9 #if defined(OS_CHROMEOS)
10 #include "base/task_runner_util.h"
11 #include "base/threading/worker_pool.h"
12 #include "chromeos/dbus/dbus_thread_manager.h"
13 #include "chromeos/dbus/lorgnette_manager_client.h"
14 #include "chromeos/dbus/pipe_reader.h"
15 #endif // OS_CHROMEOS
16 #include "content/public/browser/browser_thread.h"
17 #include "extensions/browser/extension_system.h"
18 #if defined(OS_CHROMEOS)
19 #include "third_party/cros_system_api/dbus/service_constants.h"
20 #endif // OS_CHROMEOS
21
22 using content::BrowserThread;
23 using std::string;
24 using std::vector;
25
26 namespace {
27
28 const char kImageScanFailedError[] = "Image scan failed";
29 const char kScannerImageMimeTypePng[] = "image/png";
30 const char kScannerNotAvailable[] = "Scanner not available";
31 const char kScanFunctionNotImplementedError[] = "Scan function not implemented";
32 const char kUserGestureRequiredError[] =
33 "User gesture required to perform scan";
34 const char kPngImageDataUrlPrefix[] = "data:image/png;base64,";
35 } // namespace
36
37 namespace extensions {
38
39 namespace api {
40
41 #if defined(OS_CHROMEOS)
mef 2014/10/13 15:59:54 Suggest: split into 3 files: document_scan_interf
Paul Stewart 2014/10/14 19:28:31 Done, except for consistency sake with the generat
42 class DocumentScanInterfaceImpl : public DocumentScanInterface {
43 public:
44 DocumentScanInterfaceImpl() {}
45 virtual ~DocumentScanInterfaceImpl() {}
46
47 virtual void ListScanners(
48 const ListScannersResultsCallback& callback) OVERRIDE;
49 virtual void Scan(const string& scanner_name,
50 ScanMode mode,
51 int resolution_dpi,
52 const ScanResultsCallback& callback) OVERRIDE;
53
54 private:
55 void OnScannerListReceived(
56 const ListScannersResultsCallback& callback,
57 bool succeeded,
58 const chromeos::LorgnetteManagerClient::ScannerTable &scanners);
59 void OnScanCompleted(const ScanResultsCallback &callback, bool succeeded);
60 void OnScanDataCompleted();
61 string GetImageURL(string image_data);
62
63 scoped_ptr<chromeos::PipeReaderForString> pipe_reader_;
64 string scanned_image_data_;
65
66 DISALLOW_COPY_AND_ASSIGN(DocumentScanInterfaceImpl);
67 };
68
69 void DocumentScanInterfaceImpl::ListScanners(
70 const ListScannersResultsCallback& callback) {
71 chromeos::DBusThreadManager::Get()->GetLorgnetteManagerClient()->
72 ListScanners(base::Bind(
73 &DocumentScanInterfaceImpl::OnScannerListReceived,
74 base::Unretained(this),
75 callback));
76 }
77
78 void DocumentScanInterfaceImpl::OnScannerListReceived(
79 const ListScannersResultsCallback& callback,
80 bool succeeded,
81 const chromeos::LorgnetteManagerClient::ScannerTable &scanners) {
82 vector<ScannerDescription> scanner_descriptions;
83 for (chromeos::LorgnetteManagerClient::ScannerTable::const_iterator iter =
84 scanners.begin();
85 iter != scanners.end();
86 ++iter) {
87 ScannerDescription description;
88 description.name = iter->first;
89 const chromeos::LorgnetteManagerClient::ScannerTableEntry &entry =
90 iter->second;
91 chromeos::LorgnetteManagerClient::ScannerTableEntry::const_iterator info_it;
92 info_it = entry.find(lorgnette::kScannerPropertyManufacturer);
93 if (info_it != entry.end()) {
94 description.manufacturer = info_it->second;
95 }
96 info_it = entry.find(lorgnette::kScannerPropertyModel);
97 if (info_it != entry.end()) {
98 description.model = info_it->second;
99 }
100 info_it = entry.find(lorgnette::kScannerPropertyType);
101 if (info_it != entry.end()) {
102 description.scanner_type = info_it->second;
103 }
104 description.image_mime_type = kScannerImageMimeTypePng;
105 scanner_descriptions.push_back(description);
106 }
107 callback.Run(scanner_descriptions, "");
108 }
109
110 void DocumentScanInterfaceImpl::Scan(const string& scanner_name,
111 ScanMode mode,
112 int resolution_dpi,
113 const ScanResultsCallback& callback) {
114 VLOG(1) << "Choosing scanner " << scanner_name;
115 chromeos::LorgnetteManagerClient::ScanProperties properties;
116 switch (mode) {
117 case kScanModeColor:
118 properties.mode = lorgnette::kScanPropertyModeColor;
119 break;
120
121 case kScanModeGray:
122 properties.mode = lorgnette::kScanPropertyModeGray;
123 break;
124
125 case kScanModeLineart:
126 properties.mode = lorgnette::kScanPropertyModeLineart;
127 break;
128
129 default:
130 // Leave the mode parameter empty, thereby using the default.
131 break;
132 }
133
134 if (resolution_dpi != 0) {
135 properties.resolution_dpi = resolution_dpi;
136 }
137
138 const bool kTasksAreSlow = true;
139 scoped_refptr<base::TaskRunner> task_runner =
140 base::WorkerPool::GetTaskRunner(kTasksAreSlow);
141
142 pipe_reader_.reset(new chromeos::PipeReaderForString(
143 task_runner,
144 base::Bind(&DocumentScanInterfaceImpl::OnScanDataCompleted,
145 base::Unretained(this))));
146 base::File file = pipe_reader_->StartIO();
147 base::PlatformFile platform_file = file.TakePlatformFile();
148 VLOG(1) << "ScanImage platform_file is " << platform_file;
149 chromeos::DBusThreadManager::Get()->GetLorgnetteManagerClient()->
150 ScanImage(scanner_name, platform_file, properties,
151 base::Bind(&DocumentScanInterfaceImpl::OnScanCompleted,
152 base::Unretained(this),
153 callback));
154 }
155
156 void DocumentScanInterfaceImpl::OnScanCompleted(
157 const ScanResultsCallback &callback, bool succeeded) {
158 VLOG(1) << "ScanImage returns " << succeeded;
159 if (pipe_reader_.get()) {
160 pipe_reader_->OnDataReady(-1); // terminate data stream
161 }
162
163 string error_string;
164 if (!succeeded) {
165 error_string = kImageScanFailedError;
166 }
167
168 vector<string> scanned_image_data_array;
169 scanned_image_data_array.push_back(GetImageURL(scanned_image_data_));
170 callback.Run(
171 document_scan::Scan::Results::Create(
172 scanned_image_data_array, kScannerImageMimeTypePng), error_string);
173 }
174
175 string DocumentScanInterfaceImpl::GetImageURL(string image_data) {
176 string image_data_base64;
177 base::Base64Encode(image_data, &image_data_base64);
178 return string(kPngImageDataUrlPrefix) + image_data_base64;
179 }
180
181 void DocumentScanInterfaceImpl::OnScanDataCompleted() {
182 pipe_reader_->GetData(&scanned_image_data_);
183 pipe_reader_.reset();
184 }
185
186 #else // OS_CHROMEOS
187 class DocumentScanInterfaceImpl : public DocumentScanInterface {
mef 2014/10/13 15:59:54 If this is not implemented and not intended for im
Paul Stewart 2014/10/14 19:28:31 The intent is to make it possible to implement thi
188 public:
189 DocumentScanInterfaceImpl() {}
190 virtual ~DocumentScanInterfaceImpl() {}
191
192 virtual void ListScanners(
193 const ListScannersResultsCallback& callback) OVERRIDE {
194 callback.Run(vector<ScannerDescription> (), "");
195 }
196 virtual void Scan(const string& scanner_name,
197 ScanMode mode,
198 int resolution_dpi,
199 const ScanResultsCallback& callback) OVERRIDE {
200 vector<string> null_scan_results;
201 callback.Run(document_scan::Scan::Results::Create(null_scan_results, ""),
202 kScanFunctionNotImplementedError);
203 }
204
205 private:
206 DISALLOW_COPY_AND_ASSIGN(DocumentScanInterfaceImpl);
207 };
208 #endif // OS_CHROMEOS
209
210 DocumentScanScanFunction::DocumentScanScanFunction()
211 : document_scan_interface_(new DocumentScanInterfaceImpl()) {}
212
213 DocumentScanScanFunction::~DocumentScanScanFunction() {}
214
215 bool DocumentScanScanFunction::Prepare() {
216 set_work_thread_id(BrowserThread::FILE);
217 params_ = document_scan::Scan::Params::Create(*args_);
218 EXTENSION_FUNCTION_VALIDATE(params_.get());
219 return true;
220 }
221
222 void DocumentScanScanFunction::AsyncWorkStart() {
223 if (!user_gesture()) {
224 error_ = kUserGestureRequiredError;
225 AsyncWorkCompleted();
226 return;
227 }
228
229 // Add a reference, which is balanced in OnScannerListReceived to keep the
230 // object around and allow the callback to be invoked.
231 AddRef();
232
233 document_scan_interface_->ListScanners(
234 base::Bind(&DocumentScanScanFunction::OnScannerListReceived,
235 base::Unretained(this)));
236 }
237
238 void DocumentScanScanFunction::OnScannerListReceived(
239 const vector<DocumentScanInterface::ScannerDescription>&
240 scanner_descriptions,
241 const string& error) {
242 vector<DocumentScanInterface::ScannerDescription>::const_iterator
243 scanner_i = scanner_descriptions.begin();
244 if (params_->options.accepted_mime_types) {
245 vector<string>& accepted_types =
246 *params_->options.accepted_mime_types.get();
247 for (; scanner_i != scanner_descriptions.end(); ++scanner_i) {
248 if (std::find(accepted_types.begin(), accepted_types.end(),
249 scanner_i->image_mime_type) != accepted_types.end()) {
250 break;
251 }
252 }
253 }
254
255 if (scanner_i == scanner_descriptions.end()) {
256 vector<string> null_scan_results;
257 results_ = document_scan::Scan::Results::Create(null_scan_results, "");
258 error_ = kScannerNotAvailable;
259 AsyncWorkCompleted();
260
261 // Balance the AddRef in AsyncWorkStart().
262 Release();
263 return;
264 }
265
266 // TODO(pstew): Display a user interface for choosing a scanner.
267 // This is where the scan mode, DPI, etc, would be specified.
268
269 document_scan_interface_->Scan(
270 scanner_i->name,
271 DocumentScanInterface::kScanModeColor,
272 0,
273 base::Bind(&DocumentScanScanFunction::OnResultsReceived,
274 base::Unretained(this)));
275 }
276
277 void DocumentScanScanFunction::OnResultsReceived(
278 scoped_ptr<base::ListValue> results, const string& error) {
279 // TODO(pstew): Display receied scan in the UI and confirm that this
280 // scan should be sent to the caller. If this is a multi-page scan,
281 // provide a means for adding additional scanned images up to the
282 // requested limit.
283 results_ = results.Pass();
284 error_ = error;
285 AsyncWorkCompleted();
286
287 // Balance the AddRef in AsyncWorkStart().
288 Release();
289 }
290
291 bool DocumentScanScanFunction::Respond() {
292 return error_.empty();
293 }
294
295 } // namespace api
296
297 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698