Commit 7cf1750e authored by Kyra Moed's avatar Kyra Moed Committed by Commit Bot

scanning: Support JPG file format in ScanService

Implement conversion from PNG to JPG image format when requested by user
on scanning UI. Add unit tests to verify functionality.

Bug: b:161237869
Change-Id: I8d21a0d7ddff0ddb3635b45b133f3869ec3e61cf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2507574
Commit-Queue: Kyra Moed <kmoed@google.com>
Reviewed-by: default avatarJesse Schettler <jschettler@chromium.org>
Cr-Commit-Position: refs/heads/master@{#823330}
parent baec4bfb
......@@ -4,6 +4,7 @@
#include "chrome/browser/chromeos/scanning/scan_service.h"
#include <cstdint>
#include <utility>
#include "base/bind.h"
......@@ -15,6 +16,8 @@
#include "base/time/time.h"
#include "chrome/browser/chromeos/scanning/lorgnette_scanner_manager.h"
#include "chrome/browser/chromeos/scanning/scanning_type_converters.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_util.h"
namespace chromeos {
......@@ -25,6 +28,22 @@ namespace mojo_ipc = scanning::mojom;
// Path to the active user's "My files" folder.
constexpr char kActiveUserMyFilesPath[] = "/home/chronos/user/MyFiles";
// The conversion quality when converting from PNG to JPG.
constexpr int kJpgQuality = 100;
// Converts |png_img| to JPG.
std::string PngToJpg(const std::string& png_img) {
std::vector<uint8_t> jpg_img;
const gfx::Image img = gfx::Image::CreateFrom1xPNGBytes(
reinterpret_cast<const unsigned char*>(png_img.c_str()), png_img.size());
if (!gfx::JPEG1xEncodedDataFromImage(img, kJpgQuality, &jpg_img)) {
LOG(ERROR) << "Failed to convert image from PNG to JPG.";
return "";
}
return std::string(jpg_img.begin(), jpg_img.end());
}
} // namespace
ScanService::ScanService(LorgnetteScannerManager* lorgnette_scanner_manager,
......@@ -132,18 +151,30 @@ void ScanService::OnPageReceived(const base::FilePath& scan_to_path,
const mojo_ipc::FileType file_type,
std::string scanned_image,
uint32_t page_number) {
// TODO(jschettler): Add support for converting the scanned image to other
// file types.
if (file_type != mojo_ipc::FileType::kPng) {
std::string filename;
std::string file_ext;
switch (file_type) {
case mojo_ipc::FileType::kPng:
file_ext = "png";
break;
case mojo_ipc::FileType::kJpg:
file_ext = "jpg";
scanned_image = PngToJpg(scanned_image);
if (scanned_image == "") {
save_failed_ = true;
return;
}
break;
default:
LOG(ERROR) << "Selected file type not supported.";
save_failed_ = true;
return;
}
const std::string filename = base::StringPrintf(
"scan_%02d%02d%02d-%02d%02d%02d_%d.png", start_time_.year,
filename = base::StringPrintf(
"scan_%02d%02d%02d-%02d%02d%02d_%d.%s", start_time_.year,
start_time_.month, start_time_.day_of_month, start_time_.hour,
start_time_.minute, start_time_.second, page_number);
start_time_.minute, start_time_.second, page_number, file_ext.c_str());
const auto file_path = scan_to_path.Append(filename);
if (!base::WriteFile(file_path, scanned_image)) {
LOG(ERROR) << "Failed to save scanned image: " << file_path.value().c_str();
......
......@@ -4,8 +4,11 @@
#include "chrome/browser/chromeos/scanning/scan_service.h"
#include <map>
#include <string>
#include <vector>
#include "base/containers/flat_set.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
......@@ -222,19 +225,24 @@ TEST_F(ScanServiceTest, Scan) {
base::Time::Exploded scan_time;
// Since we're using mock time, this is deterministic.
base::Time::Now().LocalExplode(&scan_time);
base::FilePath saved_scan_path = temp_dir_.GetPath().Append(
base::StringPrintf("scan_%02d%02d%02d-%02d%02d%02d_1.png", scan_time.year,
scan_time.month, scan_time.day_of_month,
scan_time.hour, scan_time.minute, scan_time.second));
EXPECT_FALSE(base::PathExists(saved_scan_path));
// Saving scanned images is currently only supported for the PNG file type.
scan_service_.SetMyFilesPathForTesting(temp_dir_.GetPath());
mojo_ipc::ScanSettings settings;
settings.scan_to_path = temp_dir_.GetPath();
settings.file_type = mojo_ipc::FileType::kPng;
std::map<std::string, mojo_ipc::FileType> file_types = {
{"png", mojo_ipc::FileType::kPng}, {"jpg", mojo_ipc::FileType::kJpg}};
base::FilePath saved_scan_path;
for (const auto& type : file_types) {
saved_scan_path = temp_dir_.GetPath().Append(base::StringPrintf(
"scan_%02d%02d%02d-%02d%02d%02d_1.%s", scan_time.year, scan_time.month,
scan_time.day_of_month, scan_time.hour, scan_time.minute,
scan_time.second, type.first.c_str()));
EXPECT_FALSE(base::PathExists(saved_scan_path));
settings.file_type = type.second;
EXPECT_TRUE(Scan(scanners[0]->id, settings.Clone()));
EXPECT_TRUE(base::PathExists(saved_scan_path));
}
}
} // namespace chromeos
......@@ -26,7 +26,7 @@ import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bun
import {getScanService} from './mojo_interface_provider.js';
import {ScannerArr} from './scanning_app_types.js';
import {colorModeFromString, pageSizeFromString, tokenToString} from './scanning_app_util.js';
import {colorModeFromString, fileTypeFromString, pageSizeFromString, tokenToString} from './scanning_app_util.js';
/**
* The default save directory for completed scans.
......@@ -227,10 +227,10 @@ Polymer({
return;
}
// TODO(jschettler): Remove this once ScanService supports other file types.
if (this.selectedFileType !==
chromeos.scanning.mojom.FileType.kPng.toString()) {
this.statusText_ = 'PNG is the only supported file type.';
// TODO(jschettler): Remove this once ScanService supports PDF.
if (this.selectedFileType ==
chromeos.scanning.mojom.FileType.kPdf.toString()) {
this.statusText_ = 'PDF is not a supported file type.';
return;
}
......@@ -238,12 +238,10 @@ Polymer({
this.settingsDisabled_ = true;
this.scanButtonDisabled_ = true;
// TODO(jschettler): Use the selected file type when ScanService supports
// it.
const settings = {
'sourceName': this.selectedSource,
'scanToPath': {'path': this.selectedFilePath},
'fileType': chromeos.scanning.mojom.FileType.kPng,
'fileType': fileTypeFromString(this.selectedFileType),
'colorMode': colorModeFromString(this.selectedColorMode),
'pageSize': pageSizeFromString(this.selectedPageSize),
'resolutionDpi': Number(this.selectedResolution),
......
......@@ -24,6 +24,26 @@ export function colorModeFromString(colorModeString) {
}
}
/**
* Converts a chromeos.scanning.mojom.FileType string to the corresponding
* enum value.
* @param {string} fileTypeString
* @return {chromeos.scanning.mojom.FileType}
*/
export function fileTypeFromString(fileTypeString) {
switch (fileTypeString) {
case chromeos.scanning.mojom.FileType.kJpg.toString():
return chromeos.scanning.mojom.FileType.kJpg;
case chromeos.scanning.mojom.FileType.kPdf.toString():
return chromeos.scanning.mojom.FileType.kPdf;
case chromeos.scanning.mojom.FileType.kPng.toString():
return chromeos.scanning.mojom.FileType.kPng;
default:
assertNotReached();
return chromeos.scanning.mojom.FileType.kPdf;
}
}
/**
* Converts a chromeos.scanning.mojom.ColorMode to a string that can be
* displayed in the color mode dropdown.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment