Ubuntu
7zip
Electron

Electronアプリケーションで、7zipから画像を取得して表示する

More than 1 year has passed since last update.

Zipファイルから画像ファイルを読み込むのは、なんとか成功したので次は、本来の目的である7zipファイルからの読み込みに挑戦してみました。

今回利用したライブラリは、node-7zです。

このライブラリは、p7zip-fullというコマンドのラッパーとなります。

p7zip-fullは、

圧縮・展開: 7z, ZIP, GZIP, BZIP2, XZ, TAR

展開のみ: APM, ARJ, CAB, CHM, CPIO, CramFS, DEB, DMG, FAT, HFS, ISO,LZH, LZMA, LZMA2, MBR, MSI, MSLZ, NSIS, NTFS, RAR (non-free のp7zip-rar パッケージがインストールされている場合のみ), RPM, SquashFS,UDF, VHD, WIM, XAR, Z

に対応しているみたいです。(マルチプラットフォームにも対応)

下記のコマンドで、ライブラリをインストールします。


command

$ sudo apt-get install p7zip-full

$ npm install node-7z --save-dev


注意点

執筆時(2016/7/6)の時点では、node-7zは、version 0.4.0がインストールされます。

このバージョンを利用するとlistが、1件しか取れません。

Githubのコミットリストを見るとpull requestが上がっており、もともとバグがあったか、p7zip-fullのバージョンアップに置いていかれたのかな?という感じです。

どちらにしてもマトモに利用できません。

p7zip-fullのバージョンを落とすことも考えたのですが、Githubから最新のコードを取得して、node_modulesのコードに上書きしたところ、動いたので、とりあえずの対応として、このまま行くことにしました。

おそらく近々に、version 0.4.1がリリースされると思います。


読み込み処理

p7zip-fullをjavascriptから呼び出すラッパークラスを利用しているため一旦ファイルをディスク上に作成して読み込む必要があります。

node-zipとは違いストリーム処理できない、残念な処理ですね。

もっと良い案が浮かべばチャレンジしてみたいと思います。


index.html

<!DOCTYPE html>

<html>

<head>
<meta charset="UTF-8">
<title>image from zip file</title>
<link rel="stylesheet" href="https://storage.googleapis.com/code.getmdl.io/1.0.0/material.indigo-pink.min.css">
<script src="https://storage.googleapis.com/code.getmdl.io/1.0.0/material.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="./js/base64-encode.js"></script>
</head>

<body>
<h1>ファイルを選択してください。</h1>
We are using node <script>document.write(process.versions.node)</script>, Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
<div class="container">
<button id="fileSelect" type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--accent mdl-js-ripple-effect">ファイル選択</button>
</div>
<div><ul id="imageContainer"></ul></div>
<script>
// node_integrationを行うとmodule.exports関係の事情でjQuery/$がundefinedになるので
// それの回避コード
window.jQuery = window.$ = require('./js/jquery-3.0.0.min.js');
</script>
<script>
var remote = require('remote');
var dialog = remote.require('dialog');
var browserWindow = remote.require('browser-window');
var fs = require('fs');

$(function(){
// ボタンが押されたときの挙動
$('#fileSelect').on('click', function(){
var focusedWindow = browserWindow.getFocusedWindow();

dialog.showOpenDialog(focusedWindow, {
properties: ['openFile'],
filters: [{
name: '圧縮ファイル',
extensions: ['zip', '7z']
}]
}, function(files) {
files.forEach(function(file) {
console.log(file);

var Zip = require('node-7z');
var archive = new Zip();

archive.list(file, { raw:[ '-i!*.jpg', '-i!*.png' ], })
.progress(function (zfile) {
//console.dir(zfile);

zfile.forEach(function(zipfile)
{
var filename = zipfile.name;
console.log('name = ' + filename);

archive.extract(file, './temp', { wildcards:[filename] })
.then(function () {
console.log('Extracting done!');
console.log('./temp/' + filename);

fs.readFile('./temp/'+filename, 'binary', function(err, data) {
if (err) throw err;

var type = filename.split('.');
var kind = 'jpeg';
if (type[type.length - 1].toLowerCase() == 'png') {
kind = 'png';
}
var dataURI = 'data:image/' + kind + ';base64,' + base64_encode(data);
var imageContainer = document.getElementById('imageContainer');
var img = document.createElement('img');

img.addEventListener("load", function () {
var li = document.createElement('li');
li.appendChild(this);
imageContainer.appendChild(li);
});
img.setAttribute("src", dataURI);

fs.unlink('./temp/'+filename, function (err)
{
if (err) throw err;
});
});
});
});
})
.then(function () {
console.log('List done!');
});
});
});
});
});
</script>
</body>

</html>