Merge pull request #1 from kovidgoyal/master

Update fork
This commit is contained in:
Jony 2020-02-09 13:11:13 +01:00 committed by GitHub
commit a66a2ea3f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2440 changed files with 152202 additions and 215273 deletions

View File

@ -1,34 +0,0 @@
os: Visual Studio 2015
clone_folder: C:\calibre
clone_depth: 5
cache:
- .build-cache
- node_modules -> .appveyor.yml
install:
- ps: Install-Product node 7
- node --version
- npm --version
- appveyor-retry npm install --no-optional rapydscript-ng regenerator uglify-js
- set PATH=node_modules\.bin;%PATH%
- rapydscript --version
environment:
SW: C:\sw
QMAKE: C:\sw\qt\bin\qmake.exe
QT_PLUGIN_PATH: C:\sw\qt\plugins
platform:
- x64
- x86
before_build:
- C:\Python36-x64\python.exe setup/win-ci.py sw
build_script:
- C:\sw\private\python\python.exe setup/win-ci.py build
test_script:
- C:\sw\private\python\python.exe setup/win-ci.py test

14
.gitattributes vendored
View File

@ -38,3 +38,17 @@
# Prevent certain files from being exported:
.gitattributes export-ignore
.gitignore export-ignore
# Mark vendored files
resources/mathjax/* linguist-vendored=true
resources/coffee-script.js linguist-vendored=true
resources/csscolorparser.js linguist-vendored=true
resources/viewer/hyphen* linguist-vendored=true
resources/viewer/jquery* linguist-vendored=true
src/hunspell linguist-vendored=true
# Mark generated files
resources/content-server/index-generated.html linguist-generated=true
resources/editor.js linguist-generated=true
resources/viewer.js linguist-generated=true
resources/viewer.html linguist-generated=true

3
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,3 @@
patreon: kovidgoyal
liberapay: kovidgoyal
custom: https://calibre-ebook.com/donate

63
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,63 @@
name: CI
on: [push, pull_request]
jobs:
test:
name: Test on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-2016]
steps:
- name: Checkout source code
uses: actions/checkout@master
with:
fetch-depth: 10
- name: Set up Python
uses: actions/setup-python@master
with:
python-version: 3.7
- name: Install calibre dependencies
run:
python setup/unix-ci.py install
- name: Bootstrap calibre
run:
python setup/unix-ci.py bootstrap
- name: Test calibre
run:
python setup/unix-ci.py test
archtest:
name: Test on Arch
runs-on: ubuntu-latest
container:
image: 'archlinux/base:latest'
env:
CI: 'true'
CALIBRE_PY3_PORT: '1'
steps:
- name: Install calibre dependencies
run: |
set -xe
useradd -m ci
pacman -Syu --noconfirm
pacman -S --noconfirm --needed base-devel sudo git sip chmlib icu jxrlib hunspell libmtp libusbx libwmf optipng podofo python-apsw python-beautifulsoup4 python-cssselect python-css-parser python-dateutil python-dbus python-dnspython python-dukpy python-feedparser python-html2text python-html5-parser python-lxml python-markdown python-mechanize python-msgpack python-netifaces python-unrardll python-pillow python-psutil python-pygments python-pyqt5 python-regex python-zeroconf python-pyqtwebengine qt5-x11extras qt5-svg qt5-imageformats udisks2 hyphen
- name: Checkout source code
uses: actions/checkout@master
with:
fetch-depth: 10
- name: Bootstrap calibre
run: |
chown -R ci:users $GITHUB_WORKSPACE
runuser -u ci -- python setup.py bootstrap --ephemeral
- name: Test calibre
run: |
runuser -u ci -- python setup.py test
chmod +777 .git .git/config

6
.gitignore vendored
View File

@ -15,6 +15,7 @@ build
dist
docs
resources/localization
resources/hyphenation
resources/scripts.calibre_msgpack
resources/ebook-convert-complete.calibre_msgpack
resources/builtin_recipes.xml
@ -28,8 +29,7 @@ resources/viewer.html
resources/content-server/index-generated.html
resources/content-server/calibre.appcache
resources/content-server/locales.zip
resources/content-server/mathjax.zip.xz
resources/content-server/mathjax.version
resources/mathjax
resources/mozilla-ca-certs.pem
resources/user-agent-data.json
icons/icns/*.iconset
@ -52,3 +52,5 @@ recipes/debug
/.metadata/
.idea
/*env*/
cmake-build-*
bypy/b

View File

@ -1,19 +0,0 @@
language: node_js
nodejs:
- node
cache:
directories:
- node_modules
- .build-cache
matrix:
include:
- os: linux
sudo: false
- os: osx
before_install:
- python setup/unix-ci.py install
- python setup/unix-ci.py bootstrap
script: python setup/unix-ci.py test

138
COPYRIGHT
View File

@ -1,13 +1,9 @@
Files: *
Copyright: Copyright (C) 2008-2017 Kovid Goyal <kovid@kovidgoyal.net>
Copyright: Copyright (C) 2008-2020 Kovid Goyal <kovid@kovidgoyal.net>
License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/duktape/*
Copyright: Various
License: MIT
Files: resources/content-server/font-awesome/*
Copyright: Various
License: MIT and SIL OFL
@ -202,12 +198,6 @@ License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/calibre/ebooks/textile/unsmarten.py
Copyright: 2011, Leigh Parry <leighparry@blueyonder.co.uk>
License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/calibre/ebooks/textile/functions.py
Copyright: 2011, Leigh Parry <leighparry@blueyonder.co.uk>
License: BSD-3-clause-like
@ -252,16 +242,6 @@ License: LGPL 2.1
The full text of the LGPL is distributed as in
/usr/share/common-licenses/LGPL-2.1 on Debian systems.
Files: src/calibre/ebooks/BeautifulSoup.py
Copyright: Copyright (c) 2004-2007, Leonard Richardson
License: BSD
The full text of the BSD license is distributed as in
/usr/share/common-licenses/BSD on Debian systems.
Files: src/hunspell/*
Copyright: Various
License: GPL-2+
Files: src/calibre/gui2/tweak_book/diff/_patiencediff_c.c
Copyright: Canonical
License: GPL-2+
@ -348,12 +328,6 @@ License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/calibre/ebooks/BeautifulSoup.py
Copyright: Copyright (c) 2004-2007, Leonard Richardson
License: BSD
The full text of the BSD license is distributed as in
/usr/share/common-licenses/BSD on Debian systems.
Files: src/calibre/ebooks/rtf2xml/*
Copyright: copyright 2002 Paul Henry Tremblay
License: GPL
@ -399,6 +373,9 @@ Files: src/calibre/translations/msgfmt.py
Copyright: Martin v. Loewis
License: Python Software Foundation License
Files: src/calibre/utils/imageops/ordered_dither.cpp
Copyright: Copyright 1999-2019 ImageMagick Studio LLC
License: ImageMagick License
BSD License (for all the BSD licensed code indicated above)
-----------------------------------------------------------
@ -581,3 +558,110 @@ whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
ImageMagick License (for all the ImageMagick licensed code indicated above)
-----------------------------------------------------------
Before we get to the text of the license, lets just review what the license says in simple terms:
It allows you to:
* freely download and use ImageMagick software, in whole or in part, for personal, company internal, or commercial purposes;
* use ImageMagick software in packages or distributions that you create;
* link against a library under a different license;
* link code under a different license against a library under this license;
* merge code into a work under a different license;
* extend patent grants to any code using code under this license;
* and extend patent protection.
It forbids you to:
* redistribute any piece of ImageMagick-originated software without proper attribution;
* use any marks owned by ImageMagick Studio LLC in any way that might state or imply that ImageMagick Studio LLC endorses your distribution;
* use any marks owned by ImageMagick Studio LLC in any way that might state or imply that you created the ImageMagick software in question.
It requires you to:
* include a copy of the license in any redistribution you may make that includes ImageMagick software;
* provide clear attribution to ImageMagick Studio LLC for any distributions that include ImageMagick software.
It does not require you to:
* include the source of the ImageMagick software itself, or of any modifications you may have made to it, in any redistribution you may assemble that includes it;
* submit changes that you make to the software back to the ImageMagick Studio LLC (though such feedback is encouraged).
A few other clarifications include:
* ImageMagick is freely available without charge;
* you may include ImageMagick on a DVD as long as you comply with the terms of the license;
* you can give modified code away for free or sell it under the terms of the ImageMagick license or distribute the result under a different license, but you need to acknowledge the use of the ImageMagick software;
* the license is compatible with the GPL V3.
* when exporting the ImageMagick software, review its export classification.
Terms and Conditions for Use, Reproduction, and Distribution
The legally binding and authoritative terms and conditions for use, reproduction, and distribution of ImageMagick follow:
Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization dedicated to making software imaging solutions freely available.
1. Definitions.
License shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
Legal Entity shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, control means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
You (or Your) shall mean an individual or Legal Entity exercising permissions granted by this License.
Source form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
Object form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
Work shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
Derivative Works shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
Contribution shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as Not a Contribution.
Contributor shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
* You must give any other recipients of the Work or Derivative Works a copy of this License; and
* You must cause any modified files to carry prominent notices stating that You changed the files; and
* You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
* If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
How to Apply the License to your Work
To apply the ImageMagick License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information (don't include the brackets). The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the ImageMagick License (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy
of the License at
https://imagemagick.org/script/license.php
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
<https://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -18,7 +18,7 @@
\pard\plain \ltrpar\s9\cf0\qc{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\rtlch\af4\afs28\lang1081\ab\ltrch\dbch\af4\langfe255\hich\f4\fs28\lang9226\b\loch\f4\fs28\lang9226\b {\rtlch \ltrch\loch\f4\fs28\lang9226\i0\b GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007}
\par \pard\plain \ltrpar\s9\cf0\qc{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\rtlch\af4\afs28\lang1081\ab\ltrch\dbch\af4\langfe255\hich\f4\fs28\lang9226\b\loch\f4\fs28\lang9226\b
\par \pard\plain \ltrpar\s9\cf0\qc{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\rtlch\af4\afs20\lang1081\ltrch\dbch\af4\langfe255\hich\f4\fs20\lang9226\loch\f4\fs20\lang9226
\par \pard\plain \ltrpar\s9\cf0\qj{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\rtlch\af5\afs20\lang1081\ltrch\dbch\af4\langfe255\hich\f5\fs20\lang9226\loch\f5\fs20\lang9226 {\rtlch \ltrch\loch\f5\fs20\lang9226\i0\b0 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>}
\par \pard\plain \ltrpar\s9\cf0\qj{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\rtlch\af5\afs20\lang1081\ltrch\dbch\af4\langfe255\hich\f5\fs20\lang9226\loch\f5\fs20\lang9226 {\rtlch \ltrch\loch\f5\fs20\lang9226\i0\b0 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>}
\par \pard\plain \ltrpar\s9\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ql\rtlch\af5\afs20\lang1081\ltrch\dbch\af4\langfe255\hich\f5\fs20\lang9226\loch\f5\fs20\lang9226 {\rtlch \ltrch\loch\f5\fs20\lang9226\i0\b0 Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.}
\par \pard\plain \ltrpar\s9\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ql\rtlch\af4\afs20\lang1081\ltrch\dbch\af4\langfe255\hich\f4\fs20\lang9226\loch\f4\fs20\lang9226
\par \pard\plain \ltrpar\s9\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ql\rtlch\af5\afs20\lang1081\ltrch\dbch\af4\langfe255\hich\f5\fs20\lang9226\loch\f5\fs20\lang9226 {\rtlch \ltrch\loch\f5\fs20\lang9226\i0\b0 Preamble}

View File

@ -10,8 +10,7 @@ reading. It is cross platform, running on Linux, Windows and macOS.
For more information, see the [calibre About page](https://calibre-ebook.com/about)
[![Build Status](https://api.travis-ci.org/kovidgoyal/calibre.svg)](https://travis-ci.org/kovidgoyal/calibre)
[![Build status](https://ci.appveyor.com/api/projects/status/v3nkfq0t3pse8lep?svg=true&passingText=windows%20OK&failingText=windows%20KO)](https://ci.appveyor.com/project/kovidgoyal/calibre)
[![Build Status](https://github.com/kovidgoyal/calibre/workflows/Continuous%20Integration/badge.svg)](https://github.com/kovidgoyal/calibre/actions?workflow=Continuous+Integration)
## Screenshots
@ -39,3 +38,7 @@ calibre is a result of the efforts of many volunteers from all over the world.
If you find it useful, please consider contributing to support its development.
[Donate to support calibre development](https://calibre-ebook.com/donate).
## Building calibre binaries
See [Build instructions](bypy/README.rst) for instructions on how to build the
calibre binaries and installers for all the platforms calibre supports.

29
README.python3 Normal file
View File

@ -0,0 +1,29 @@
Efforts to port calibre to python 3 are ongoing. calibre can be run
using python3 under Linux. To do so, install python 3, checkout calibre
from source with
git clone git@github.com:kovidgoyal/calibre.git && cd calibre
Then, setup calibre to run under python2, with:
python2 setup.py bootstrap
Check that calibre works, with:
python2 run-local calibre
Now build the calibre C extensions for python 3 with:
CALIBRE_PY3_PORT=1 python3 setup.py build
You should now be able to run the calibre test suite using:
CALIBRE_PY3_PORT=1 python3 setup.py test
And run calibre itself (which may not work) with:
python3 run-local calibre
For the status of the port, and discussion of its design, see
https://github.com/kovidgoyal/calibre/pull/870

134
bypy/README.rst Normal file
View File

@ -0,0 +1,134 @@
Build the calibre installers, including all dependencies from scratch
=======================================================================
This folder contains code to automate the process of building calibre,
including all its dependencies, from scratch, for all platforms that calibre
supports.
In general builds proceed in two steps, first build all the dependencies, then
build the calibre installer itself.
Requirements
---------------
Building *must* run on a Linux computer.
First create some empty top level directory and run the following commands::
git clone https://github.com/kovidgoyal/bypy.git
git clone https://github.com/kovidgoyal/calibre.git
cd calibre
./setup.py bootstrap
To make the Windows and macOS builds it uses VirtualBox VMs. Instructions on
creating the VMs are in their respective sections below.
Linux
-------
To build the 64bit and 32bit dependencies for calibre, run::
./setup.py build_dep linux
./setup.py build_dep linux 32
The output (after a very long time) will be in :literal:`bypy/b/linux/[32|64]`
Now you can build the calibre Linux tarballs with::
./setup.py linux
The output will be in :literal:`dist`
macOS
--------------
You need a VirtualBox virtual machine of macOS 10.14 (Mojave). Name the
VM using ``vm_name`` from :literal:`bypy/macos.conf`. To setup macOS inside the VM,
follow the steps:
* Turn on Remote Login under Network (SSHD)
* Create a user account named ``kovid`` and enable password-less login for SSH
for that account (setup ``~/.ssh/authorized_keys``)
* Setup ssh into the VM from the host using the ``vm_name`` from above.
* Install the needed software mentioned in :literal:`bypy/macos.conf`.
To build the dependencies for calibre, run::
./setup.py build_dep macos
The output (after a very long time) will be in :literal:`bypy/b/macos`.
Now you can build the calibre ``.dmg`` with::
./setup.py osx --dont-sign --dont-notarize
The output will be in :literal:`dist`
Windows
-------------
You need a VirtualBox virtual machine of Windows 7 64bit. Name the
VM using ``vm_name`` from :literal:`bypy/windows.conf`. To setup windows inside the VM,
follow the steps:
* Install all the software mentioned in :literal:`bypy/windows.conf`
* Install cygwin, with the: vim, dos2unix, rsync, openssh, unzip, wget, make, zsh, patch, bash-completion, curl
packages
* Edit ``/etc/passwd`` and replace all occurrences of ``/bin/bash`` with ``/bin/zsh`` (in
a cygwin prompt)
* Setup a password for your windows user account
* Follow the steps here: http://pcsupport.about.com/od/windows7/ht/auto-logon-windows-7.htm to allow the
machine to bootup without having to enter the password
* The following steps must all be run in an administrator cygwin shell, to
enable SSH logins to the machine
* First clean out any existing cygwin ssh setup with::
net stop sshd
cygrunsrv -R sshd
net user sshd /DELETE
net user cyg_server /DELETE (delete any other cygwin users account you
can list them with net user)
rm -R /etc/ssh*
mkpasswd -cl > /etc/passwd
mkgroup --local > /etc/group
* Assign the necessary rights to the normal user account (administrator
cygwin command prompt needed - editrights is available in ``\cygwin\bin``)::
editrights.exe -a SeAssignPrimaryTokenPrivilege -u kovid
editrights.exe -a SeCreateTokenPrivilege -u kovid
editrights.exe -a SeTcbPrivilege -u kovid
editrights.exe -a SeServiceLogonRight -u kovid
* Run::
ssh-host-config
And answer (yes) to all questions. If it asks do you want to use a
different user name, specify the name of your user account and enter
username and password
* Start sshd with::
net start sshd
* See http://www.kgx.net.nz/2010/03/cygwin-sshd-and-windows-7/ for details
To build the dependencies for calibre, run::
./setup.py build_dep windows
./setup.py build_dep windows 32
The output (after a very long time) will be in :literal:`bypy/b/windows/[32|64]`.
Now you can build the calibre windows installers with::
./setup.py win --dont-sign
The output will be in :literal:`dist`

195
bypy/init_env.py Normal file
View File

@ -0,0 +1,195 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import print_function
import json
import os
import re
import subprocess
import sys
from bypy.constants import (
LIBDIR, PREFIX, PYTHON, SRC as CALIBRE_DIR, build_dir, islinux, ismacos,
iswindows, worker_env
)
from bypy.utils import run_shell
dlls = [
'Core',
'Concurrent',
'Gui',
'Network',
# 'NetworkAuth',
'Location',
'PrintSupport',
'WebChannel',
# 'WebSockets',
# 'WebView',
'Positioning',
'PositioningQuick',
'Sensors',
'Sql',
'Svg',
'WebEngineCore',
'WebEngine',
'WebEngineWidgets',
'Widgets',
# 'Multimedia',
'OpenGL',
'Quick',
'QuickWidgets',
'Qml',
'QmlModels',
# 'MultimediaWidgets',
'Xml',
# 'XmlPatterns',
]
if islinux:
dlls += ['X11Extras', 'XcbQpa', 'WaylandClient', 'DBus']
elif ismacos:
dlls += ['MacExtras', 'DBus']
elif iswindows:
dlls += ['WinExtras']
QT_DLLS = frozenset(
'Qt5' + x for x in dlls
)
QT_PLUGINS = [
'imageformats',
'iconengines',
# 'mediaservice',
'platforms',
'platformthemes',
# 'playlistformats',
'sqldrivers',
# 'webview',
# 'audio', 'printsupport', 'bearer', 'position',
]
if islinux:
QT_PLUGINS += [
'platforminputcontexts',
'wayland-decoration-client',
'wayland-graphics-integration-client',
'wayland-shell-integration',
'xcbglintegrations',
]
else:
QT_PLUGINS.append('styles')
PYQT_MODULES = (
'Qt',
'QtCore',
'QtGui',
'QtNetwork',
# 'QtMultimedia', 'QtMultimediaWidgets',
'QtPrintSupport',
'QtSensors',
'QtSvg',
'QtWidgets',
'QtWebEngine',
'QtWebEngineCore',
'QtWebEngineWidgets',
'QtWebChannel',
)
del dlls
if iswindows:
PYQT_MODULES += ('QtWinExtras',)
def read_cal_file(name):
with open(os.path.join(CALIBRE_DIR, 'src', 'calibre', name), 'rb') as f:
return f.read().decode('utf-8')
def initialize_constants():
calibre_constants = {}
src = read_cal_file('constants.py')
nv = re.search(r'numeric_version\s+=\s+\((\d+), (\d+), (\d+)\)', src)
calibre_constants['version'
] = '%s.%s.%s' % (nv.group(1), nv.group(2), nv.group(3))
calibre_constants['appname'] = re.search(
r'__appname__\s+=\s+(u{0,1})[\'"]([^\'"]+)[\'"]', src
).group(2)
epsrc = re.compile(r'entry_points = (\{.*?\})',
re.DOTALL).search(read_cal_file('linux.py')).group(1)
entry_points = eval(epsrc, {'__appname__': calibre_constants['appname']})
def e2b(ep):
return re.search(r'\s*(.*?)\s*=', ep).group(1).strip()
def e2s(ep, base='src'):
return (
base + os.path.sep +
re.search(r'.*=\s*(.*?):', ep).group(1).replace('.', '/') + '.py'
).strip()
def e2m(ep):
return re.search(r'.*=\s*(.*?)\s*:', ep).group(1).strip()
def e2f(ep):
return ep[ep.rindex(':') + 1:].strip()
calibre_constants['basenames'] = basenames = {}
calibre_constants['functions'] = functions = {}
calibre_constants['modules'] = modules = {}
calibre_constants['scripts'] = scripts = {}
for x in ('console', 'gui'):
y = x + '_scripts'
basenames[x] = list(map(e2b, entry_points[y]))
functions[x] = list(map(e2f, entry_points[y]))
modules[x] = list(map(e2m, entry_points[y]))
scripts[x] = list(map(e2s, entry_points[y]))
src = read_cal_file('ebooks/__init__.py')
be = re.search(
r'^BOOK_EXTENSIONS\s*=\s*(\[.+?\])', src, flags=re.DOTALL | re.MULTILINE
).group(1)
calibre_constants['book_extensions'] = json.loads(be.replace("'", '"'))
return calibre_constants
def run(*args, **extra_env):
env = os.environ.copy()
env.update(worker_env)
env.update(extra_env)
env['SW'] = PREFIX
env['LD_LIBRARY_PATH'] = LIBDIR
env['SIP_BIN'] = os.path.join(PREFIX, 'bin', 'sip')
env['QMAKE'] = os.path.join(PREFIX, 'qt', 'bin', 'qmake')
return subprocess.call(list(args), env=env, cwd=CALIBRE_DIR)
def build_c_extensions(ext_dir, args):
bdir = os.path.join(build_dir(), 'calibre-extension-objects')
cmd = [
PYTHON, 'setup.py', 'build',
'--output-dir', ext_dir, '--build-dir', bdir,
]
if args.build_only:
cmd.extend(('--only', args.build_only))
if run(*cmd, COMPILER_CWD=bdir) != 0:
print('Building of calibre C extensions failed', file=sys.stderr)
os.chdir(CALIBRE_DIR)
run_shell()
raise SystemExit('Building of calibre C extensions failed')
return ext_dir
def run_tests(path_to_calibre_debug, cwd_on_failure):
ret = run(path_to_calibre_debug, '--test-build')
if ret != 0:
os.chdir(cwd_on_failure)
print(
'running calibre build tests failed with return code:', ret, 'and exe:', path_to_calibre_debug, file=sys.stderr)
run_shell()
raise SystemExit('running calibre build tests failed')
if __name__ == 'program':
calibre_constants = initialize_constants()

4
bypy/linux.conf Normal file
View File

@ -0,0 +1,4 @@
image 'https://partner-images.canonical.com/core/xenial/current/ubuntu-xenial-core-cloudimg-{}-root.tar.gz'
# Build time deps for Qt. See http://doc.qt.io/qt-5/linux-requirements.html and https://wiki.qt.io/Building_Qt_5_from_Git
deps 'flex bison gperf ruby libx11-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libx11-xcb-dev libxcb-glx0-dev xkb-data libglu1-mesa-dev libxkbcommon-dev libinput-dev libxkbcommon-x11-dev libgtk2.0-dev libvulkan-dev libwayland-dev libwayland-egl1-mesa libegl1-mesa-dev libxtst-dev libnss3-dev libfreetype6-dev libfontconfig-dev'

308
bypy/linux/__main__.py Normal file
View File

@ -0,0 +1,308 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import print_function
import errno
import glob
import os
import shutil
import stat
import subprocess
import tarfile
import time
from functools import partial
from bypy.constants import (
OUTPUT_DIR, PREFIX, SRC as CALIBRE_DIR, is64bit, python_major_minor_version
)
from bypy.utils import (
create_job, get_dll_path, mkdtemp, parallel_build, py_compile, run, walk
)
j = os.path.join
self_dir = os.path.dirname(os.path.abspath(__file__))
arch = 'x86_64' if is64bit else 'i686'
py_ver = '.'.join(map(str, python_major_minor_version()))
QT_PREFIX = os.path.join(PREFIX, 'qt')
iv = globals()['init_env']
calibre_constants = iv['calibre_constants']
QT_DLLS, QT_PLUGINS, PYQT_MODULES = iv['QT_DLLS'], iv['QT_PLUGINS'], iv['PYQT_MODULES']
qt_get_dll_path = partial(get_dll_path, loc=os.path.join(QT_PREFIX, 'lib'))
def binary_includes():
return [
j(PREFIX, 'bin', x) for x in ('pdftohtml', 'pdfinfo', 'pdftoppm', 'optipng', 'JxrDecApp')] + [
j(PREFIX, 'private', 'mozjpeg', 'bin', x) for x in ('jpegtran', 'cjpeg')] + [
] + list(map(
get_dll_path,
('usb-1.0 mtp expat sqlite3 ffi z openjp2 poppler dbus-1 iconv xml2 xslt jpeg png16'
' webp webpmux webpdemux exslt ncursesw readline chm hunspell-1.7 hyphen'
' icudata icui18n icuuc icuio gcrypt gpg-error'
' gobject-2.0 glib-2.0 gthread-2.0 gmodule-2.0 gio-2.0 dbus-glib-1').split()
)) + [
get_dll_path('podofo', 3), get_dll_path('bz2', 2), j(PREFIX, 'lib', 'libunrar.so'),
get_dll_path('ssl', 3), get_dll_path('crypto', 3), get_dll_path('python' + py_ver, 2),
# We dont include libstdc++.so as the OpenGL dlls on the target
# computer fail to load in the QPA xcb plugin if they were compiled
# with a newer version of gcc than the one on the build computer.
# libstdc++, like glibc is forward compatible and I dont think any
# distros do not have libstdc++.so.6, so it should be safe to leave it out.
# https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html (The current
# debian stable libstdc++ is libstdc++.so.6.0.17)
] + list(map(qt_get_dll_path, QT_DLLS))
class Env(object):
def __init__(self):
self.src_root = CALIBRE_DIR
self.base = mkdtemp('frozen-')
self.lib_dir = j(self.base, 'lib')
self.py_dir = j(self.lib_dir, 'python' + py_ver)
os.makedirs(self.py_dir)
self.bin_dir = j(self.base, 'bin')
os.mkdir(self.bin_dir)
self.SRC = j(self.src_root, 'src')
self.obj_dir = mkdtemp('launchers-')
def ignore_in_lib(base, items, ignored_dirs=None):
ans = []
if ignored_dirs is None:
ignored_dirs = {'.svn', '.bzr', '.git', 'test', 'tests', 'testing'}
for name in items:
path = j(base, name)
if os.path.isdir(path):
if name in ignored_dirs or not os.path.exists(j(path, '__init__.py')):
if name != 'plugins':
ans.append(name)
else:
if name.rpartition('.')[-1] not in ('so', 'py'):
ans.append(name)
return ans
def import_site_packages(srcdir, dest):
if not os.path.exists(dest):
os.mkdir(dest)
for x in os.listdir(srcdir):
ext = x.rpartition('.')[-1]
f = j(srcdir, x)
if ext in ('py', 'so'):
shutil.copy2(f, dest)
elif ext == 'pth' and x != 'setuptools.pth':
for line in open(f, 'rb').read().splitlines():
src = os.path.abspath(j(srcdir, line))
if os.path.exists(src) and os.path.isdir(src):
import_site_packages(src, dest)
elif os.path.exists(j(f, '__init__.py')):
shutil.copytree(f, j(dest, x), ignore=ignore_in_lib)
def copy_libs(env):
print('Copying libs...')
for x in binary_includes():
dest = env.bin_dir if '/bin/' in x else env.lib_dir
shutil.copy2(x, dest)
os.chmod(j(
dest, os.path.basename(x)),
stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
base = j(QT_PREFIX, 'plugins')
dest = j(env.lib_dir, '..', 'plugins')
os.mkdir(dest)
for x in QT_PLUGINS:
if x not in ('audio', 'printsupport'):
shutil.copytree(j(base, x), j(dest, x))
dest = j(env.lib_dir, '..', 'libexec')
os.mkdir(dest)
shutil.copy2(os.path.join(QT_PREFIX, 'libexec', 'QtWebEngineProcess'), dest)
def copy_python(env, ext_dir):
print('Copying python...')
srcdir = j(PREFIX, 'lib/python' + py_ver)
for x in os.listdir(srcdir):
y = j(srcdir, x)
ext = os.path.splitext(x)[1]
if os.path.isdir(y) and x not in ('test', 'hotshot',
'site-packages', 'idlelib', 'lib2to3', 'dist-packages'):
shutil.copytree(y, j(env.py_dir, x), ignore=ignore_in_lib)
if os.path.isfile(y) and ext in ('.py', '.so'):
shutil.copy2(y, env.py_dir)
srcdir = j(srcdir, 'site-packages')
dest = j(env.py_dir, 'site-packages')
import_site_packages(srcdir, dest)
shutil.rmtree(j(dest, 'PyQt5/uic/port_v3'))
filter_pyqt = {x + '.so' for x in PYQT_MODULES} | {'sip.so'}
pyqt = j(dest, 'PyQt5')
for x in os.listdir(pyqt):
if x.endswith('.so') and x not in filter_pyqt:
os.remove(j(pyqt, x))
for x in os.listdir(env.SRC):
c = j(env.SRC, x)
if os.path.exists(j(c, '__init__.py')):
shutil.copytree(c, j(dest, x), ignore=partial(ignore_in_lib, ignored_dirs={}))
elif os.path.isfile(c):
shutil.copy2(c, j(dest, x))
pdir = j(dest, 'calibre', 'plugins')
if not os.path.exists(pdir):
os.mkdir(pdir)
for x in glob.glob(j(ext_dir, '*.so')):
shutil.copy2(x, j(pdir, os.path.basename(x)))
shutil.copytree(j(env.src_root, 'resources'), j(env.base, 'resources'))
for pak in glob.glob(j(QT_PREFIX, 'resources', '*.pak')):
shutil.copy2(pak, j(env.base, 'resources'))
os.mkdir(j(env.base, 'translations'))
shutil.copytree(j(QT_PREFIX, 'translations', 'qtwebengine_locales'), j(env.base, 'translations', 'qtwebengine_locales'))
sitepy = j(self_dir, 'site.py')
shutil.copy2(sitepy, j(env.py_dir, 'site.py'))
py_compile(env.py_dir)
def build_launchers(env):
base = self_dir
sources = [j(base, x) for x in ['util.c']]
objects = [j(env.obj_dir, os.path.basename(x) + '.o') for x in sources]
cflags = '-fno-strict-aliasing -W -Wall -c -O2 -pipe -DPYTHON_VER="python%s"' % py_ver
cflags = cflags.split() + ['-I%s/include/python%s' % (PREFIX, py_ver)]
for src, obj in zip(sources, objects):
cmd = ['gcc'] + cflags + ['-fPIC', '-o', obj, src]
run(*cmd)
dll = j(env.lib_dir, 'libcalibre-launcher.so')
cmd = ['gcc', '-O2', '-Wl,--rpath=$ORIGIN/../lib', '-fPIC', '-o', dll, '-shared'] + objects + \
['-L%s/lib' % PREFIX, '-lpython' + py_ver]
run(*cmd)
src = j(base, 'main.c')
modules, basenames, functions = calibre_constants['modules'].copy(), calibre_constants['basenames'].copy(), calibre_constants['functions'].copy()
modules['console'].append('calibre.linux')
basenames['console'].append('calibre_postinstall')
functions['console'].append('main')
c_launcher = '/tmp/calibre-c-launcher'
lsrc = os.path.join(base, 'launcher.c')
cmd = ['gcc', '-O2', '-o', c_launcher, lsrc, ]
run(*cmd)
jobs = []
for typ in ('console', 'gui', ):
for mod, bname, func in zip(modules[typ], basenames[typ], functions[typ]):
xflags = list(cflags)
xflags.remove('-c')
xflags += ['-DGUI_APP=' + ('1' if typ == 'gui' else '0')]
xflags += ['-DMODULE="%s"' % mod, '-DBASENAME="%s"' % bname,
'-DFUNCTION="%s"' % func]
exe = j(env.bin_dir, bname)
cmd = ['gcc'] + xflags + [src, '-o', exe, '-L' + env.lib_dir, '-lcalibre-launcher']
jobs.append(create_job(cmd))
sh = j(env.base, bname)
shutil.copy2(c_launcher, sh)
os.chmod(sh,
stat.S_IREAD | stat.S_IEXEC | stat.S_IWRITE | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
if jobs:
if not parallel_build(jobs, verbose=False):
raise SystemExit(1)
def is_elf(path):
with open(path, 'rb') as f:
return f.read(4) == b'\x7fELF'
STRIPCMD = ['strip']
def strip_files(files, argv_max=(256 * 1024)):
""" Strip a list of files """
while files:
cmd = list(STRIPCMD)
pathlen = sum(len(s) + 1 for s in cmd)
while pathlen < argv_max and files:
f = files.pop()
cmd.append(f)
pathlen += len(f) + 1
if len(cmd) > len(STRIPCMD):
all_files = cmd[len(STRIPCMD):]
unwritable_files = tuple(filter(None, (None if os.access(x, os.W_OK) else (x, os.stat(x).st_mode) for x in all_files)))
[os.chmod(x, stat.S_IWRITE | old_mode) for x, old_mode in unwritable_files]
subprocess.check_call(cmd)
[os.chmod(x, old_mode) for x, old_mode in unwritable_files]
def strip_binaries(env):
files = {j(env.bin_dir, x) for x in os.listdir(env.bin_dir)} | {
x for x in {
j(os.path.dirname(env.bin_dir), x) for x in os.listdir(env.bin_dir)} if os.path.exists(x)}
for x in walk(env.lib_dir):
x = os.path.realpath(x)
if x not in files and is_elf(x):
files.add(x)
files.add(j(env.lib_dir, '..', 'libexec', 'QtWebEngineProcess'))
print('Stripping %d files...' % len(files))
before = sum(os.path.getsize(x) for x in files)
strip_files(files)
after = sum(os.path.getsize(x) for x in files)
print('Stripped %.1f MB' % ((before - after) / (1024 * 1024.)))
def create_tarfile(env, compression_level='9'):
print('Creating archive...')
base = OUTPUT_DIR
try:
shutil.rmtree(base)
except EnvironmentError as err:
if err.errno != errno.ENOENT:
raise
os.mkdir(base)
dist = os.path.join(base, '%s-%s-%s.tar' % (calibre_constants['appname'], calibre_constants['version'], arch))
with tarfile.open(dist, mode='w', format=tarfile.PAX_FORMAT) as tf:
cwd = os.getcwd()
os.chdir(env.base)
try:
for x in os.listdir('.'):
tf.add(x)
finally:
os.chdir(cwd)
print('Compressing archive...')
ans = dist.rpartition('.')[0] + '.txz'
start_time = time.time()
subprocess.check_call(['xz', '--threads=0', '-f', '-' + compression_level, dist])
secs = time.time() - start_time
print('Compressed in %d minutes %d seconds' % (secs // 60, secs % 60))
os.rename(dist + '.xz', ans)
print('Archive %s created: %.2f MB' % (
os.path.basename(ans), os.stat(ans).st_size / (1024.**2)))
def main():
args = globals()['args']
ext_dir = globals()['ext_dir']
run_tests = iv['run_tests']
env = Env()
copy_libs(env)
copy_python(env, ext_dir)
build_launchers(env)
if not args.skip_tests:
run_tests(j(env.base, 'calibre-debug'), env.base)
if not args.dont_strip:
strip_binaries(env)
create_tarfile(env, args.compression_level)
if __name__ == '__main__':
main()

49
bypy/linux/launcher.c Normal file
View File

@ -0,0 +1,49 @@
/*
* launcher.c
* Copyright (C) 2014 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <unistd.h>
#define PATHLEN 1023
#define SET(x, y) if (setenv(x, y, 1) != 0) { fprintf(stderr, "Failed to set environment variable with error: %s\n", strerror(errno)); return 1; }
int main(int argc, char **argv) {
static char buf[PATHLEN+1] = {0}, lib[PATHLEN+1] = {0}, base[PATHLEN+1] = {0}, exe[PATHLEN+1] = {0}, *ldp = NULL;
if (readlink("/proc/self/exe", buf, PATHLEN) == -1) {
fprintf(stderr, "Failed to read path of executable with error: %s\n", strerror(errno));
return 1;
}
strncpy(lib, buf, PATHLEN);
strncpy(base, dirname(lib), PATHLEN);
snprintf(exe, PATHLEN, "%s/bin/%s", base, basename(buf));
memset(lib, 0, PATHLEN);
snprintf(lib, PATHLEN, "%s/lib", base);
/* qt-at-spi causes crashes and performance issues in various distros, so disable it */
SET("QT_ACCESSIBILITY", "0")
SET("CALIBRE_QT_PREFIX", base)
memset(buf, 0, PATHLEN);
ldp = getenv("LD_LIBRARY_PATH");
if (ldp == NULL) strncpy(buf, lib, PATHLEN);
else snprintf(buf, PATHLEN, "%s:%s", lib, ldp);
SET("LD_LIBRARY_PATH", buf)
argv[0] = exe;
if (execv(exe, argv) == -1) {
fprintf(stderr, "Failed to execute binary: %s with error: %s\n", exe, strerror(errno));
return 1;
}
return 0;
}

13
bypy/linux/main.c Normal file
View File

@ -0,0 +1,13 @@
#include "util.h"
#include <stdlib.h>
int main(int argc, char **argv) {
int ret = 0;
set_gui_app(GUI_APP);
ret = execute_python_entrypoint(argc, argv, BASENAME, MODULE, FUNCTION, NULL, NULL);
return ret;
}

88
bypy/linux/site.py Normal file
View File

@ -0,0 +1,88 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import sys
import encodings # noqa
import __builtin__
import locale
import os
import codecs
def set_default_encoding():
try:
locale.setlocale(locale.LC_ALL, '')
except:
print ('WARNING: Failed to set default libc locale, using en_US.UTF-8')
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
try:
enc = locale.getdefaultlocale()[1]
except Exception:
enc = None
if not enc:
enc = locale.nl_langinfo(locale.CODESET)
if not enc or enc.lower() == 'ascii':
enc = 'UTF-8'
try:
enc = codecs.lookup(enc).name
except LookupError:
enc = 'UTF-8'
sys.setdefaultencoding(enc)
del sys.setdefaultencoding
class _Helper(object):
"""Define the builtin 'help'.
This is a wrapper around pydoc.help (with a twist).
"""
def __repr__(self):
return "Type help() for interactive help, " \
"or help(object) for help about object."
def __call__(self, *args, **kwds):
import pydoc
return pydoc.help(*args, **kwds)
def set_helper():
__builtin__.help = _Helper()
def setup_openssl_environment():
# Workaround for Linux distros that have still failed to get their heads
# out of their asses and implement a common location for SSL certificates.
# It's not that hard people, there exists a wonderful tool called the symlink
# See http://www.mobileread.com/forums/showthread.php?t=256095
if b'SSL_CERT_FILE' not in os.environ and b'SSL_CERT_DIR' not in os.environ:
if os.access('/etc/pki/tls/certs/ca-bundle.crt', os.R_OK):
os.environ['SSL_CERT_FILE'] = '/etc/pki/tls/certs/ca-bundle.crt'
elif os.path.isdir('/etc/ssl/certs'):
os.environ['SSL_CERT_DIR'] = '/etc/ssl/certs'
def main():
try:
sys.argv[0] = sys.calibre_basename
dfv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
if dfv and os.path.exists(dfv):
sys.path.insert(0, os.path.abspath(dfv))
set_default_encoding()
set_helper()
setup_openssl_environment()
mod = __import__(sys.calibre_module, fromlist=[1])
func = getattr(mod, sys.calibre_function)
return func()
except SystemExit as err:
if err.code is None:
return 0
if isinstance(err.code, int):
return err.code
print (err.code)
return 1
except:
import traceback
traceback.print_exc()
return 1

262
bypy/linux/util.c Normal file
View File

@ -0,0 +1,262 @@
#include "util.h"
#include <Python.h>
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include <errno.h>
static bool GUI_APP = False;
static char exe_path[PATH_MAX];
static char base_dir[PATH_MAX];
static char bin_dir[PATH_MAX];
static char lib_dir[PATH_MAX];
static char extensions_dir[PATH_MAX];
static char resources_dir[PATH_MAX];
void set_gui_app(bool yes) { GUI_APP = yes; }
int report_error(const char *msg, int code) {
fprintf(stderr, "%s\n", msg);
return code;
}
int report_libc_error(const char *msg) {
char buf[2000];
int err = errno;
snprintf(buf, 2000, "%s::%s", msg, strerror(err));
return report_error(buf, err);
}
int pyobject_to_int(PyObject *res) {
int ret = 0; PyObject *tmp;
if (res != NULL) {
tmp = PyNumber_Int(res);
if (tmp == NULL) ret = (PyObject_IsTrue(res)) ? 1 : 0;
else ret = (int)PyInt_AS_LONG(tmp);
}
return ret;
}
int handle_sysexit(PyObject *e) {
PyObject *code;
code = PyObject_GetAttrString(e, "code");
if (!code) return 0;
return pyobject_to_int(code);
}
int report_python_error(const char *preamble, int code) {
PyObject *exc, *val, *tb, *str;
int ret, issysexit = 0; char *i, *buf;
if (!PyErr_Occurred()) return code;
issysexit = PyErr_ExceptionMatches(PyExc_SystemExit);
PyErr_Fetch(&exc, &val, &tb);
if (exc != NULL) {
PyErr_NormalizeException(&exc, &val, &tb);
if (issysexit) {
return (val) ? handle_sysexit(val) : 0;
}
if (val != NULL) {
str = PyObject_Unicode(val);
if (str == NULL) {
PyErr_Clear();
str = PyObject_Str(val);
}
i = PyString_AsString(str);
if (i == NULL) OOM;
buf = (char*)calloc(strlen(i)+strlen(preamble)+5, sizeof(char));
if (buf == NULL) OOM;
sprintf(buf, "%s::%s", preamble, i);
ret = report_error(buf, code);
if (buf) free(buf);
if (tb != NULL) {
PyErr_Restore(exc, val, tb);
PyErr_Print();
}
return ret;
}
}
return report_error(preamble, code);
}
static void get_paths()
{
char linkname[256]; /* /proc/<pid>/exe */
char *p;
pid_t pid;
int ret;
pid = getpid();
if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid) < 0)
{
/* This should only happen on large word systems. I'm not sure
what the proper response is here.
Since it really is an assert-like condition, aborting the
program seems to be in order. */
exit(report_error("PID too large", EXIT_FAILURE));
}
ret = readlink(linkname, exe_path, sizeof(exe_path));
if (ret == -1) {
exit(report_error("Failed to read exe path.", EXIT_FAILURE));
}
if ((size_t)ret >= sizeof(exe_path)) {
exit(report_error("exe path buffer too small.", EXIT_FAILURE));
}
exe_path[ret] = 0;
p = rindex(exe_path, '/');
if (p == NULL) {
exit(report_error("No path separators in executable path", EXIT_FAILURE));
}
strncat(base_dir, exe_path, p - exe_path);
p = rindex(base_dir, '/');
if (p == NULL) {
exit(report_error("Only one path separator in executable path", EXIT_FAILURE));
}
*p = 0;
if (strlen(base_dir) == 0) {
exit(report_error("base directory empty", EXIT_FAILURE));
}
snprintf(bin_dir, sizeof(bin_dir), "%s/bin", base_dir);
snprintf(lib_dir, sizeof(lib_dir), "%s/lib", base_dir);
snprintf(resources_dir, sizeof(resources_dir), "%s/resources", base_dir);
snprintf(extensions_dir, sizeof(extensions_dir), "%s/%s/site-packages/calibre/plugins", lib_dir, PYTHON_VER);
}
void setup_stream(const char *name, const char *errors) {
PyObject *stream;
char buf[100];
snprintf(buf, 20, "%s", name);
stream = PySys_GetObject(buf);
snprintf(buf, 20, "%s", "utf-8");
snprintf(buf+21, 30, "%s", errors);
if (!PyFile_SetEncodingAndErrors(stream, buf, buf+21))
exit(report_python_error("Failed to set stream encoding", 1));
}
void setup_streams() {
if (!GUI_APP) { // Remove buffering
setvbuf(stdin, NULL, _IONBF, 2);
setvbuf(stdout, NULL, _IONBF, 2);
setvbuf(stderr, NULL, _IONBF, 2);
}
/*setup_stream("stdin", "strict");
setup_stream("stdout", "strict");
setup_stream("stderr", "strict");*/
}
void initialize_interpreter(int argc, char **argv, char *outr, char *errr,
const char *basename, const char *module, const char *function) {
char *encoding, *p;
get_paths();
char path[3*PATH_MAX];
snprintf(path, sizeof(path),
"%s/%s:%s/%s/plat-linux2:%s/%s/lib-dynload:%s/%s/site-packages",
lib_dir, PYTHON_VER, lib_dir, PYTHON_VER, lib_dir, PYTHON_VER,
lib_dir, PYTHON_VER);
Py_OptimizeFlag = 2;
Py_NoSiteFlag = 1;
Py_DontWriteBytecodeFlag = 1;
Py_IgnoreEnvironmentFlag = 1;
Py_NoUserSiteDirectory = 1;
Py_VerboseFlag = 0;
Py_DebugFlag = 0;
Py_HashRandomizationFlag = 1;
Py_SetProgramName(exe_path);
Py_SetPythonHome(base_dir);
//printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath());
Py_Initialize();
if (!Py_FileSystemDefaultEncoding) {
encoding = getenv("PYTHONIOENCODING");
if (encoding != NULL) {
Py_FileSystemDefaultEncoding = strndup(encoding, 20);
p = index(Py_FileSystemDefaultEncoding, ':');
if (p != NULL) *p = 0;
} else
Py_FileSystemDefaultEncoding = strndup("UTF-8", 10);
}
setup_streams();
PySys_SetArgv(argc, argv);
//printf("Path after Py_Initialize(): %s\r\n\n", Py_GetPath());
PySys_SetPath(path);
//printf("Path set by me: %s\r\n\n", path);
PySys_SetObject("gui_app", PyBool_FromLong((long)GUI_APP));
PySys_SetObject("calibre_basename", PyBytes_FromString(basename));
PySys_SetObject("calibre_module", PyBytes_FromString(module));
PySys_SetObject("calibre_function", PyBytes_FromString(function));
PySys_SetObject("extensions_location", PyBytes_FromString(extensions_dir));
PySys_SetObject("resources_location", PyBytes_FromString(resources_dir));
PySys_SetObject("executables_location", PyBytes_FromString(base_dir));
PySys_SetObject("frozen_path", PyBytes_FromString(base_dir));
PySys_SetObject("frozen", Py_True);
Py_INCREF(Py_True);
if (GUI_APP && outr && errr) {
// PySys_SetObject("stdout_redirect", PyUnicode_FromWideChar(outr, wcslen(outr)));
// PySys_SetObject("stderr_redirect", PyUnicode_FromWideChar(errr, wcslen(outr)));
}
}
int execute_python_entrypoint(int argc, char **argv, const char *basename, const char *module, const char *function,
char *outr, char *errr) {
PyObject *site, *pmain, *res;
int ret = 0;
initialize_interpreter(argc, argv, outr, errr, basename, module, function);
site = PyImport_ImportModule("site");
if (site == NULL)
ret = report_python_error("Failed to import site module", 1);
else {
Py_XINCREF(site);
pmain = PyObject_GetAttrString(site, "main");
if (pmain == NULL || !PyCallable_Check(pmain))
ret = report_python_error("site module has no main function", 1);
else {
Py_XINCREF(pmain);
res = PyObject_CallObject(pmain, NULL);
if (res == NULL)
ret = report_python_error("Python function terminated unexpectedly", 1);
ret = pyobject_to_int(res);
}
}
PyErr_Clear();
Py_Finalize();
//printf("11111 Returning: %d\r\n", ret);
return ret;
}

18
bypy/linux/util.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#define UNICODE
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#define OOM exit(report_error("Out of memory", EXIT_FAILURE))
#define True 1
#define False 0
typedef int bool;
void set_gui_app(bool yes);
int execute_python_entrypoint(int argc, char **argv, const char *basename,
const char *module, const char *function,
char *outr, char *errr);

6
bypy/macos.conf Normal file
View File

@ -0,0 +1,6 @@
# Requires installation of XCode 10.2 and Python 3.7 and
# python3 -m pip install certifi
vm_name 'calibre-macos-build'
root '/Users/Shared/calibre-build'
python '/Library/Frameworks/Python.framework/Versions/3.7/bin/python3'

782
bypy/macos/__main__.py Normal file
View File

@ -0,0 +1,782 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import absolute_import, division, print_function, unicode_literals
import errno
import glob
import json
import operator
import os
import plistlib
import runpy
import shutil
import stat
import subprocess
import sys
import tempfile
import time
import zipfile
from functools import partial, reduce
from itertools import repeat
from bypy.constants import (
OUTPUT_DIR, PREFIX, PYTHON, SRC as CALIBRE_DIR, python_major_minor_version
)
from bypy.utils import current_dir, mkdtemp, py_compile, timeit, walk
abspath, join, basename, dirname = os.path.abspath, os.path.join, os.path.basename, os.path.dirname
iv = globals()['init_env']
calibre_constants = iv['calibre_constants']
QT_DLLS, QT_PLUGINS, PYQT_MODULES = iv['QT_DLLS'], iv['QT_PLUGINS'], iv['PYQT_MODULES']
py_ver = '.'.join(map(str, python_major_minor_version()))
sign_app = runpy.run_path(join(dirname(abspath(__file__)), 'sign.py'))['sign_app']
QT_PREFIX = join(PREFIX, 'qt')
QT_FRAMEWORKS = [x.replace('5', '') for x in QT_DLLS]
ENV = dict(
FONTCONFIG_PATH='@executable_path/../Resources/fonts',
FONTCONFIG_FILE='@executable_path/../Resources/fonts/fonts.conf',
PYTHONIOENCODING='UTF-8',
SSL_CERT_FILE='@executable_path/../Resources/resources/mozilla-ca-certs.pem',
)
APPNAME, VERSION = calibre_constants['appname'], calibre_constants['version']
basenames, main_modules, main_functions = calibre_constants['basenames'], calibre_constants['modules'], calibre_constants['functions']
def compile_launcher_lib(contents_dir, gcc, base):
print('\tCompiling calibre_launcher.dylib')
fd = join(contents_dir, 'Frameworks')
dest = join(fd, 'calibre-launcher.dylib')
src = join(base, 'util.c')
cmd = [gcc] + '-Wall -dynamiclib -std=gnu99'.split() + [src] + \
['-I' + base] + \
['-I%s/python/Python.framework/Versions/Current/Headers' % PREFIX] + \
'-current_version 1.0 -compatibility_version 1.0'.split() + \
'-fvisibility=hidden -o'.split() + [dest] + \
['-install_name',
'@executable_path/../Frameworks/' + os.path.basename(dest)] + \
[('-F%s/python' % PREFIX), '-framework', 'Python', '-framework', 'CoreFoundation', '-headerpad_max_install_names']
# print('\t'+' '.join(cmd))
sys.stdout.flush()
subprocess.check_call(cmd)
return dest
gcc = os.environ.get('CC', 'clang')
def compile_launchers(contents_dir, xprograms, pyver):
base = dirname(abspath(__file__))
lib = compile_launcher_lib(contents_dir, gcc, base)
with open(join(base, 'launcher.c'), 'rb') as f:
src = f.read().decode('utf-8')
env, env_vals = [], []
for key, val in ENV.items():
env.append('"%s"' % key)
env_vals.append('"%s"' % val)
env = ', '.join(env) + ', '
env_vals = ', '.join(env_vals) + ', '
src = src.replace('/*ENV_VARS*/', env)
src = src.replace('/*ENV_VAR_VALS*/', env_vals)
programs = [lib]
for program, x in xprograms.items():
module, func, ptype = x
print('\tCompiling', program)
out = join(contents_dir, 'MacOS', program)
programs.append(out)
psrc = src.replace('**PROGRAM**', program)
psrc = psrc.replace('**MODULE**', module)
psrc = psrc.replace('**FUNCTION**', func)
psrc = psrc.replace('**PYVER**', pyver)
psrc = psrc.replace('**IS_GUI**', ('1' if ptype == 'gui' else '0'))
fsrc = '/tmp/%s.c' % program
with open(fsrc, 'wb') as f:
f.write(psrc.encode('utf-8'))
cmd = [gcc, '-Wall', '-I' + base, fsrc, lib, '-o', out,
'-headerpad_max_install_names']
# print('\t'+' '.join(cmd))
sys.stdout.flush()
subprocess.check_call(cmd)
return programs
def flipwritable(fn, mode=None):
"""
Flip the writability of a file and return the old mode. Returns None
if the file is already writable.
"""
if os.access(fn, os.W_OK):
return None
old_mode = os.stat(fn).st_mode
os.chmod(fn, stat.S_IWRITE | old_mode)
return old_mode
STRIPCMD = ['/usr/bin/strip', '-x', '-S', '-']
def strip_files(files, argv_max=(256 * 1024)):
"""
Strip a list of files
"""
tostrip = [(fn, flipwritable(fn)) for fn in files if os.path.exists(fn)]
while tostrip:
cmd = list(STRIPCMD)
flips = []
pathlen = reduce(operator.add, [len(s) + 1 for s in cmd])
while pathlen < argv_max:
if not tostrip:
break
added, flip = tostrip.pop()
pathlen += len(added) + 1
cmd.append(added)
flips.append((added, flip))
else:
cmd.pop()
tostrip.append(flips.pop())
os.spawnv(os.P_WAIT, cmd[0], cmd)
for args in flips:
flipwritable(*args)
def flush(func):
def ff(*args, **kwargs):
sys.stdout.flush()
sys.stderr.flush()
ret = func(*args, **kwargs)
sys.stdout.flush()
sys.stderr.flush()
return ret
return ff
class Freeze(object):
FID = '@executable_path/../Frameworks'
def __init__(self, build_dir, ext_dir, test_runner, test_launchers=False, dont_strip=False, sign_installers=False, notarize=False):
self.build_dir = os.path.realpath(build_dir)
self.sign_installers = sign_installers
self.notarize = notarize
self.ext_dir = os.path.realpath(ext_dir)
self.test_runner = test_runner
self.dont_strip = dont_strip
self.contents_dir = join(self.build_dir, 'Contents')
self.resources_dir = join(self.contents_dir, 'Resources')
self.frameworks_dir = join(self.contents_dir, 'Frameworks')
self.exe_dir = join(self.contents_dir, 'MacOS')
self.helpers_dir = join(self.contents_dir, 'utils.app', 'Contents', 'MacOS')
self.site_packages = join(self.resources_dir, 'Python', 'site-packages')
self.to_strip = []
self.warnings = []
self.run(test_launchers)
def run(self, test_launchers):
ret = 0
if not test_launchers:
if os.path.exists(self.build_dir):
shutil.rmtree(self.build_dir)
os.makedirs(self.build_dir)
self.create_skeleton()
self.create_plist()
self.add_python_framework()
self.add_site_packages()
self.add_stdlib()
self.add_qt_frameworks()
self.add_calibre_plugins()
self.add_podofo()
self.add_poppler()
self.add_imaging_libs()
self.add_fontconfig()
self.add_misc_libraries()
self.add_resources()
self.compile_py_modules()
self.copy_site()
self.create_exe()
if not test_launchers and not self.dont_strip:
self.strip_files()
if not test_launchers:
self.create_gui_apps()
self.run_tests()
ret = self.makedmg(self.build_dir, APPNAME + '-' + VERSION)
return ret
@flush
def run_tests(self):
self.test_runner(join(self.contents_dir, 'MacOS', 'calibre-debug'), self.contents_dir)
@flush
def add_resources(self):
shutil.copytree('resources', join(self.resources_dir,
'resources'))
@flush
def strip_files(self):
print('\nStripping files...')
strip_files(self.to_strip)
@flush
def create_exe(self):
print('\nCreating launchers')
programs = {}
progs = []
for x in ('console', 'gui'):
progs += list(zip(basenames[x], main_modules[x], main_functions[x], repeat(x)))
for program, module, func, ptype in progs:
programs[program] = (module, func, ptype)
programs = compile_launchers(self.contents_dir, programs, py_ver)
for out in programs:
self.fix_dependencies_in_lib(out)
@flush
def set_id(self, path_to_lib, new_id):
old_mode = flipwritable(path_to_lib)
subprocess.check_call(['install_name_tool', '-id', new_id, path_to_lib])
if old_mode is not None:
flipwritable(path_to_lib, old_mode)
@flush
def get_dependencies(self, path_to_lib):
install_name = subprocess.check_output(['otool', '-D', path_to_lib]).splitlines()[-1].strip()
raw = subprocess.check_output(['otool', '-L', path_to_lib]).decode('utf-8')
for line in raw.splitlines():
if 'compatibility' not in line or line.strip().endswith(':'):
continue
idx = line.find('(')
path = line[:idx].strip()
yield path, path == install_name
@flush
def get_local_dependencies(self, path_to_lib):
for x, is_id in self.get_dependencies(path_to_lib):
if x.startswith('@rpath/Qt'):
yield x, x[len('@rpath/'):], is_id
else:
for y in (PREFIX + '/lib/', PREFIX + '/python/Python.framework/'):
if x.startswith(y):
if y == PREFIX + '/python/Python.framework/':
y = PREFIX + '/python/'
yield x, x[len(y):], is_id
break
@flush
def change_dep(self, old_dep, new_dep, is_id, path_to_lib):
cmd = ['-id', new_dep] if is_id else ['-change', old_dep, new_dep]
subprocess.check_call(['install_name_tool'] + cmd + [path_to_lib])
@flush
def fix_dependencies_in_lib(self, path_to_lib):
self.to_strip.append(path_to_lib)
old_mode = flipwritable(path_to_lib)
for dep, bname, is_id in self.get_local_dependencies(path_to_lib):
ndep = self.FID + '/' + bname
self.change_dep(dep, ndep, is_id, path_to_lib)
ldeps = list(self.get_local_dependencies(path_to_lib))
if ldeps:
print('\nFailed to fix dependencies in', path_to_lib)
print('Remaining local dependencies:', ldeps)
raise SystemExit(1)
if old_mode is not None:
flipwritable(path_to_lib, old_mode)
@flush
def add_python_framework(self):
print('\nAdding Python framework')
src = join(PREFIX + '/python', 'Python.framework')
x = join(self.frameworks_dir, 'Python.framework')
curr = os.path.realpath(join(src, 'Versions', 'Current'))
currd = join(x, 'Versions', basename(curr))
rd = join(currd, 'Resources')
os.makedirs(rd)
shutil.copy2(join(curr, 'Resources', 'Info.plist'), rd)
shutil.copy2(join(curr, 'Python'), currd)
self.set_id(join(currd, 'Python'),
self.FID + '/Python.framework/Versions/%s/Python' % basename(curr))
# The following is needed for codesign in OS X >= 10.9.5
with current_dir(x):
os.symlink(basename(curr), 'Versions/Current')
for y in ('Python', 'Resources'):
os.symlink('Versions/Current/%s' % y, y)
@flush
def add_qt_frameworks(self):
print('\nAdding Qt Frameworks')
for f in QT_FRAMEWORKS:
self.add_qt_framework(f)
pdir = join(QT_PREFIX, 'plugins')
ddir = join(self.contents_dir, 'PlugIns')
os.mkdir(ddir)
for x in QT_PLUGINS:
shutil.copytree(join(pdir, x), join(ddir, x))
for l in glob.glob(join(ddir, '*/*.dylib')):
self.fix_dependencies_in_lib(l)
x = os.path.relpath(l, ddir)
self.set_id(l, '@executable_path/' + x)
webengine_process = join(
self.frameworks_dir, 'QtWebEngineCore.framework/Versions/5/Helpers/QtWebEngineProcess.app/Contents/MacOS/QtWebEngineProcess')
self.fix_dependencies_in_lib(webengine_process)
cdir = dirname(dirname(webengine_process))
dest = join(cdir, 'Frameworks')
os.symlink(os.path.relpath(self.frameworks_dir, cdir), dest)
def add_qt_framework(self, f):
libname = f
f = f + '.framework'
src = join(PREFIX, 'qt', 'lib', f)
ignore = shutil.ignore_patterns('Headers', '*.h', 'Headers/*')
dest = join(self.frameworks_dir, f)
shutil.copytree(src, dest, symlinks=True,
ignore=ignore)
lib = os.path.realpath(join(dest, libname))
rpath = os.path.relpath(lib, self.frameworks_dir)
self.set_id(lib, self.FID + '/' + rpath)
self.fix_dependencies_in_lib(lib)
# The following is needed for codesign in OS X >= 10.9.5
# The presence of the .prl file in the root of the framework causes
# codesign to fail.
with current_dir(dest):
for x in os.listdir('.'):
if x != 'Versions' and not os.path.islink(x):
os.remove(x)
@flush
def create_skeleton(self):
c = join(self.build_dir, 'Contents')
for x in ('Frameworks', 'MacOS', 'Resources'):
os.makedirs(join(c, x))
icons = glob.glob(join(CALIBRE_DIR, 'icons', 'icns', '*.iconset'))
if not icons:
raise SystemExit('Failed to find icns format icons')
for x in icons:
subprocess.check_call([
'iconutil', '-c', 'icns', x, '-o', join(
self.resources_dir, basename(x).partition('.')[0] + '.icns')])
for helpers in (self.helpers_dir,):
os.makedirs(helpers)
cdir = dirname(helpers)
dest = join(cdir, 'Frameworks')
src = self.frameworks_dir
os.symlink(os.path.relpath(src, cdir), dest)
dest = join(cdir, 'Resources')
src = self.resources_dir
os.symlink(os.path.relpath(src, cdir), dest)
pl = dict(
CFBundleDevelopmentRegion='English',
CFBundleDisplayName=APPNAME + ' - utils',
CFBundleName=APPNAME + '-utils',
CFBundleIdentifier='com.calibre-ebook.utils',
LSBackgroundOnly='1',
CFBundleVersion=VERSION,
CFBundleShortVersionString=VERSION,
CFBundlePackageType='APPL',
CFBundleSignature='????',
CFBundleExecutable='pdftohtml',
LSMinimumSystemVersion='10.14.0',
LSRequiresNativeExecution=True,
NSAppleScriptEnabled=False,
CFBundleIconFile='',
)
with open(join(cdir, 'Info.plist'), 'wb') as p:
plistlib.dump(pl, p)
@flush
def add_calibre_plugins(self):
dest = join(self.frameworks_dir, 'plugins')
os.mkdir(dest)
plugins = glob.glob(self.ext_dir + '/*.so')
if not plugins:
raise SystemExit('No calibre plugins found in: ' + self.ext_dir)
for f in plugins:
shutil.copy2(f, dest)
self.fix_dependencies_in_lib(join(dest, basename(f)))
if f.endswith('/podofo.so'):
self.change_dep('libpodofo.0.9.6.dylib',
'@executable_path/../Frameworks/libpodofo.0.9.6.dylib', False, join(dest, basename(f)))
@flush
def create_plist(self):
BOOK_EXTENSIONS = calibre_constants['book_extensions']
env = dict(**ENV)
env['CALIBRE_LAUNCHED_FROM_BUNDLE'] = '1'
docs = [{'CFBundleTypeName': 'E-book',
'CFBundleTypeExtensions': list(BOOK_EXTENSIONS),
'CFBundleTypeIconFile': 'book.icns',
'CFBundleTypeRole': 'Viewer',
}]
pl = dict(
CFBundleDevelopmentRegion='English',
CFBundleDisplayName=APPNAME,
CFBundleName=APPNAME,
CFBundleIdentifier='net.kovidgoyal.calibre',
CFBundleVersion=VERSION,
CFBundleShortVersionString=VERSION,
CFBundlePackageType='APPL',
CFBundleSignature='????',
CFBundleExecutable='calibre',
CFBundleDocumentTypes=docs,
LSMinimumSystemVersion='10.14.0',
LSRequiresNativeExecution=True,
NSAppleScriptEnabled=False,
NSSupportsAutomaticGraphicsSwitching=True,
NSHumanReadableCopyright=time.strftime('Copyright %Y, Kovid Goyal'),
CFBundleGetInfoString=('calibre, an E-book management '
'application. Visit https://calibre-ebook.com for details.'),
CFBundleIconFile='calibre.icns',
NSHighResolutionCapable=True,
LSApplicationCategoryType='public.app-category.productivity',
LSEnvironment=env
)
with open(join(self.contents_dir, 'Info.plist'), 'wb') as p:
plistlib.dump(pl, p)
@flush
def install_dylib(self, path, set_id=True, dest=None):
dest = dest or self.frameworks_dir
os.makedirs(dest, exist_ok=True)
shutil.copy2(path, dest)
if set_id:
self.set_id(join(dest, basename(path)),
self.FID + '/' + basename(path))
self.fix_dependencies_in_lib(join(dest, basename(path)))
@flush
def add_podofo(self):
print('\nAdding PoDoFo')
pdf = join(PREFIX, 'lib', 'libpodofo.0.9.6.dylib')
self.install_dylib(pdf)
@flush
def add_poppler(self):
print('\nAdding poppler')
for x in ('libopenjp2.7.dylib', 'libpoppler.87.dylib',):
self.install_dylib(join(PREFIX, 'lib', x))
for x in ('pdftohtml', 'pdftoppm', 'pdfinfo'):
self.install_dylib(
join(PREFIX, 'bin', x), set_id=False, dest=self.helpers_dir)
@flush
def add_imaging_libs(self):
print('\nAdding libjpeg, libpng, libwebp, optipng and mozjpeg')
for x in ('jpeg.8', 'png16.16', 'webp.7', 'webpmux.3', 'webpdemux.2'):
self.install_dylib(join(PREFIX, 'lib', 'lib%s.dylib' % x))
for x in 'optipng', 'JxrDecApp':
self.install_dylib(join(PREFIX, 'bin', x), set_id=False, dest=self.helpers_dir)
for x in ('jpegtran', 'cjpeg'):
self.install_dylib(
join(PREFIX, 'private', 'mozjpeg', 'bin', x), set_id=False, dest=self.helpers_dir)
@flush
def add_fontconfig(self):
print('\nAdding fontconfig')
for x in ('fontconfig.1', 'freetype.6', 'expat.1'):
src = join(PREFIX, 'lib', 'lib' + x + '.dylib')
self.install_dylib(src)
dst = join(self.resources_dir, 'fonts')
if os.path.exists(dst):
shutil.rmtree(dst)
src = join(PREFIX, 'etc', 'fonts')
shutil.copytree(src, dst, symlinks=False)
fc = join(dst, 'fonts.conf')
with open(fc, 'rb') as f:
raw = f.read().decode('utf-8')
raw = raw.replace('<dir>/usr/share/fonts</dir>', '''\
<dir>/Library/Fonts</dir>
<dir>/System/Library/Fonts</dir>
<dir>/usr/X11R6/lib/X11/fonts</dir>
<dir>/usr/share/fonts</dir>
<dir>/var/root/Library/Fonts</dir>
<dir>/usr/share/fonts</dir>
''')
open(fc, 'wb').write(raw.encode('utf-8'))
@flush
def add_misc_libraries(self):
for x in (
'usb-1.0.0', 'mtp.9', 'chm.0', 'sqlite3.0', 'hunspell-1.7.0',
'icudata.64', 'icui18n.64', 'icuio.64', 'icuuc.64', 'hyphen.0',
'xslt.1', 'exslt.0', 'xml2.2', 'z.1', 'unrar',
'crypto.1.0.0', 'ssl.1.0.0', 'iconv.2', # 'ltdl.7'
):
print('\nAdding', x)
x = 'lib%s.dylib' % x
src = join(PREFIX, 'lib', x)
shutil.copy2(src, self.frameworks_dir)
dest = join(self.frameworks_dir, x)
self.set_id(dest, self.FID + '/' + x)
self.fix_dependencies_in_lib(dest)
@flush
def add_site_packages(self):
print('\nAdding site-packages')
os.makedirs(self.site_packages)
sys_path = json.loads(subprocess.check_output([
PYTHON, '-c', 'import sys, json; json.dump(sys.path, sys.stdout)']))
paths = reversed(tuple(map(abspath, [x for x in sys_path if x.startswith('/') and not x.startswith('/Library/')])))
upaths = []
for x in paths:
if x not in upaths and (x.endswith('.egg') or x.endswith('/site-packages')):
upaths.append(x)
upaths.append(join(CALIBRE_DIR, 'src'))
for x in upaths:
print('\t', x)
tdir = None
try:
if not os.path.isdir(x):
zf = zipfile.ZipFile(x)
tdir = tempfile.mkdtemp()
zf.extractall(tdir)
x = tdir
self.add_modules_from_dir(x)
self.add_packages_from_dir(x)
finally:
if tdir is not None:
shutil.rmtree(tdir)
try:
shutil.rmtree(join(self.site_packages, 'calibre', 'plugins'))
except OSError as err:
if err.errno != errno.ENOENT:
raise
sp = join(self.resources_dir, 'Python', 'site-packages')
for x in os.listdir(join(sp, 'PyQt5')):
if x.endswith('.so') and x.rpartition('.')[0] not in PYQT_MODULES and x != 'sip.so':
os.remove(join(sp, 'PyQt5', x))
os.remove(join(sp, 'PyQt5', 'uic/port_v3/proxy_base.py'))
self.remove_bytecode(sp)
@flush
def add_modules_from_dir(self, src):
for x in glob.glob(join(src, '*.py')) + glob.glob(join(src, '*.so')):
dest = join(self.site_packages, os.path.basename(x))
shutil.copy2(x, dest)
if x.endswith('.so'):
self.fix_dependencies_in_lib(dest)
@flush
def add_packages_from_dir(self, src):
for x in os.listdir(src):
x = join(src, x)
if os.path.isdir(x) and os.path.exists(join(x, '__init__.py')):
if self.filter_package(basename(x)):
continue
self.add_package_dir(x)
@flush
def add_package_dir(self, x, dest=None):
def ignore(root, files):
ans = []
for y in files:
ext = os.path.splitext(y)[1]
if ext not in ('', '.py', '.so') or \
(not ext and not os.path.isdir(join(root, y))):
ans.append(y)
return ans
if dest is None:
dest = self.site_packages
dest = join(dest, basename(x))
shutil.copytree(x, dest, symlinks=True, ignore=ignore)
self.postprocess_package(x, dest)
for x in os.walk(dest):
for f in x[-1]:
if f.endswith('.so'):
f = join(x[0], f)
self.fix_dependencies_in_lib(f)
@flush
def filter_package(self, name):
return name in ('Cython', 'modulegraph', 'macholib', 'py2app',
'bdist_mpkg', 'altgraph')
@flush
def postprocess_package(self, src_path, dest_path):
pass
@flush
def add_stdlib(self):
print('\nAdding python stdlib')
src = PREFIX + '/python/Python.framework/Versions/Current/lib/python'
src += py_ver
dest = join(self.resources_dir, 'Python', 'lib', 'python')
dest += py_ver
os.makedirs(dest)
for x in os.listdir(src):
if x in ('site-packages', 'config', 'test', 'lib2to3', 'lib-tk',
'lib-old', 'idlelib', 'plat-mac', 'plat-darwin', 'site.py'):
continue
x = join(src, x)
if os.path.isdir(x):
self.add_package_dir(x, dest)
elif os.path.splitext(x)[1] in ('.so', '.py'):
shutil.copy2(x, dest)
dest2 = join(dest, basename(x))
if dest2.endswith('.so'):
self.fix_dependencies_in_lib(dest2)
target = join(self.resources_dir, 'Python', 'lib')
self.remove_bytecode(target)
for path in walk(target):
if path.endswith('.so'):
self.fix_dependencies_in_lib(path)
@flush
def remove_bytecode(self, dest):
for x in os.walk(dest):
root = x[0]
for f in x[-1]:
if os.path.splitext(f) in ('.pyc', '.pyo'):
os.remove(join(root, f))
@flush
def compile_py_modules(self):
print('\nCompiling Python modules')
base = join(self.resources_dir, 'Python')
py_compile(base)
def create_app_clone(self, name, specialise_plist, remove_doc_types=False, base_dir=None):
print('\nCreating ' + name)
base_dir = base_dir or self.contents_dir
cc_dir = join(base_dir, name, 'Contents')
exe_dir = join(cc_dir, 'MacOS')
rel_path = os.path.relpath(join(self.contents_dir, 'MacOS'), exe_dir)
os.makedirs(exe_dir)
for x in os.listdir(self.contents_dir):
if x.endswith('.app'):
continue
if x == 'Info.plist':
with open(join(self.contents_dir, x), 'rb') as r:
plist = plistlib.load(r)
specialise_plist(plist)
if remove_doc_types:
plist.pop('CFBundleDocumentTypes')
exe = plist['CFBundleExecutable']
# We cannot symlink the bundle executable as if we do,
# codesigning fails
plist['CFBundleExecutable'] = exe + '-placeholder-for-codesigning'
nexe = join(exe_dir, plist['CFBundleExecutable'])
base = os.path.dirname(abspath(__file__))
cmd = [
gcc, '-Wall', '-Werror', '-DEXE_NAME="%s"' % exe, '-DREL_PATH="%s"' % rel_path,
join(base, 'placeholder.c'), '-o', nexe, '-headerpad_max_install_names'
]
subprocess.check_call(cmd)
with open(join(cc_dir, x), 'wb') as p:
plistlib.dump(plist, p)
elif x == 'MacOS':
for item in os.listdir(join(self.contents_dir, 'MacOS')):
src = join(self.contents_dir, x, item)
os.symlink(os.path.relpath(src, exe_dir), join(exe_dir, item))
else:
src = join(self.contents_dir, x)
os.symlink(os.path.relpath(src, cc_dir), join(cc_dir, x))
@flush
def create_gui_apps(self):
def get_data(cmd):
return json.loads(subprocess.check_output([join(self.contents_dir, 'MacOS', 'calibre-debug'), '-c', cmd]))
data = get_data(
'from calibre.customize.ui import all_input_formats; import sys, json; from calibre.ebooks.oeb.polish.main import SUPPORTED;'
'sys.stdout.write(json.dumps({"i": tuple(all_input_formats()), "e": tuple(SUPPORTED)}))'
)
input_formats = sorted(set(data['i']))
edit_formats = sorted(set(data['e']))
def specialise_plist(launcher, formats, plist):
plist['CFBundleDisplayName'] = plist['CFBundleName'] = {
'ebook-viewer': 'E-book Viewer', 'ebook-edit': 'Edit Book',
}[launcher]
plist['CFBundleExecutable'] = launcher
plist['CFBundleIdentifier'] = 'com.calibre-ebook.' + launcher
plist['CFBundleIconFile'] = launcher + '.icns'
e = plist['CFBundleDocumentTypes'][0]
e['CFBundleTypeExtensions'] = [x.lower() for x in formats]
self.create_app_clone('ebook-viewer.app', partial(specialise_plist, 'ebook-viewer', input_formats))
self.create_app_clone('ebook-edit.app', partial(specialise_plist, 'ebook-edit', edit_formats),
base_dir=join(self.contents_dir, 'ebook-viewer.app', 'Contents'))
# We need to move the webengine resources into the deepest sub-app
# because the sandbox gets set to the nearest enclosing app which
# means that WebEngine will fail to access its resources when running
# in the sub-apps unless they are present inside the sub app bundle
# somewhere
base_dest = join(self.contents_dir, 'ebook-viewer.app', 'Contents', 'ebook-edit.app', 'Contents', 'SharedSupport')
os.mkdir(base_dest)
base_src = os.path.realpath(join(self.frameworks_dir, 'QtWebEngineCore.framework/Resources'))
items = [join(base_src, 'qtwebengine_locales')] + glob.glob(join(base_src, '*.pak')) + glob.glob(join(base_src, '*.dat'))
for src in items:
dest = join(base_dest, os.path.basename(src))
os.rename(src, dest)
os.symlink(os.path.relpath(dest, base_src), src)
@flush
def copy_site(self):
base = os.path.dirname(abspath(__file__))
shutil.copy2(join(base, 'site.py'), join(self.resources_dir, 'Python',
'lib', 'python' + py_ver))
@flush
def makedmg(self, d, volname, internet_enable=True):
''' Copy a directory d into a dmg named volname '''
print('\nSigning...')
sys.stdout.flush()
destdir = OUTPUT_DIR
try:
shutil.rmtree(destdir)
except EnvironmentError as err:
if err.errno != errno.ENOENT:
raise
os.mkdir(destdir)
dmg = join(destdir, volname + '.dmg')
if os.path.exists(dmg):
os.unlink(dmg)
tdir = tempfile.mkdtemp()
appdir = join(tdir, os.path.basename(d))
shutil.copytree(d, appdir, symlinks=True)
if self.sign_installers or self.notarize:
with timeit() as times:
sign_app(appdir, self.notarize)
print('Signing completed in %d minutes %d seconds' % tuple(times))
os.symlink('/Applications', join(tdir, 'Applications'))
size_in_mb = int(subprocess.check_output(['du', '-s', '-k', tdir]).decode('utf-8').split()[0]) / 1024.
# UDBZ gives the best compression, better than ULFO
cmd = ['/usr/bin/hdiutil', 'create', '-srcfolder', tdir, '-volname', volname, '-format', 'UDBZ']
if 190 < size_in_mb < 250:
# We need -size 255m because of a bug in hdiutil. When the size of
# srcfolder is close to 200MB hdiutil fails with
# diskimages-helper: resize request is above maximum size allowed.
cmd += ['-size', '255m']
print('\nCreating dmg...')
with timeit() as times:
subprocess.check_call(cmd + [dmg])
if internet_enable:
subprocess.check_call(['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg])
print('dmg created in %d minutes and %d seconds' % tuple(times))
shutil.rmtree(tdir)
size = os.stat(dmg).st_size / (1024 * 1024.)
print('\nInstaller size: %.2fMB\n' % size)
return dmg
def main(args, ext_dir, test_runner):
build_dir = abspath(join(mkdtemp('frozen-'), APPNAME + '.app'))
if args.skip_tests:
test_runner = lambda *a: None
Freeze(build_dir, ext_dir, test_runner, dont_strip=args.dont_strip, sign_installers=args.sign_installers, notarize=args.notarize)
if __name__ == '__main__':
args = globals()['args']
ext_dir = globals()['ext_dir']
run_tests = iv['run_tests']
main(args, ext_dir, run_tests)

41
bypy/macos/launcher.c Normal file
View File

@ -0,0 +1,41 @@
#include "util.h"
#include <stdlib.h>
#include <libproc.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#define fatal(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); }
#define arraysz(x) (sizeof(x)/sizeof(x[0]))
// These variables must be filled in before compiling
static const char *ENV_VARS[] = { /*ENV_VARS*/ NULL };
static const char *ENV_VAR_VALS[] = { /*ENV_VAR_VALS*/ NULL};
static char PROGRAM[] = "**PROGRAM**";
static const char MODULE[] = "**MODULE**";
static const char FUNCTION[] = "**FUNCTION**";
static const char PYVER[] = "**PYVER**";
int
main(int argc, char* const *argv, const char **envp) {
char pathbuf[PROC_PIDPATHINFO_MAXSIZE], realpath_buf[PROC_PIDPATHINFO_MAXSIZE * 5];
pid_t pid = getpid();
int ret = proc_pidpath(pid, pathbuf, arraysz(pathbuf));
if (ret <= 0) fatal("failed to get executable path for current pid with error: %s", strerror(errno));
char *path = realpath(pathbuf, realpath_buf);
if (path == NULL) fatal("failed to get realpath for executable path with error: %s", strerror(errno));
// We re-exec using an absolute path because the Qt WebEngine sandbox does not work
// when running via symlink
const int is_gui = **IS_GUI**;
if (!is_gui && strcmp(PROGRAM, "calibre-parallel") != 0 && strcmp(argv[0], path) != 0) {
char* new_argv[1024] = {0};
new_argv[0] = path;
for (int i = 1; i < argc && i < arraysz(new_argv) - 1; i++) new_argv[i] = argv[i];
execv(path, new_argv);
}
return run(ENV_VARS, ENV_VAR_VALS, PROGRAM, MODULE, FUNCTION, PYVER, is_gui, argc, argv, envp, path);
}

41
bypy/macos/placeholder.c Normal file
View File

@ -0,0 +1,41 @@
/*
* placeholder.c
* Copyright (C) 2018 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libproc.h>
#include <unistd.h>
int
main(int argc, char * const *argv, const char **envp) {
int ret;
pid_t pid;
char pathbuf[PROC_PIDPATHINFO_MAXSIZE], realpath_buf[PROC_PIDPATHINFO_MAXSIZE * 5];
pid = getpid();
ret = proc_pidpath(pid, pathbuf, sizeof(pathbuf));
if (ret <= 0) {
perror("failed to get executable path for current pid with error");
return 1;
}
char *path = realpath(pathbuf, realpath_buf);
if (path == NULL) {
perror("failed to get realpath for executable path with error");
return 1;
}
char *t = rindex(path, '/');
if (t == NULL) {
fprintf(stderr, "No / in executable path: %s\n", path);
return 1;
}
*(t + 1) = 0;
snprintf(t + 1, sizeof(realpath_buf) - strlen(path), "%s/%s", REL_PATH, EXE_NAME);
execv(path, argv);
}

253
bypy/macos/sign.py Normal file
View File

@ -0,0 +1,253 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import json
import os
import plistlib
import re
import shlex
import subprocess
import tempfile
import time
from contextlib import contextmanager
from glob import glob
from pprint import pprint
from urllib.request import urlopen
from uuid import uuid4
from bypy.utils import current_dir, run_shell, timeit
CODESIGN_CREDS = os.path.expanduser('~/cert-cred')
CODESIGN_CERT = os.path.expanduser('~/maccert.p12')
# The apple id file contains the apple id and an app specific password which
# can be generated from appleid.apple.com
# Note that apple accounts require two-factor authentication which is currntly
# setup on ox and via SMS on my phone
APPLE_ID = os.path.expanduser('~/aid')
path_to_entitlements = os.path.expanduser('~/calibre-entitlements.plist')
def run(*args):
if len(args) == 1 and isinstance(args[0], str):
args = shlex.split(args[0])
if subprocess.call(args) != 0:
raise SystemExit('Failed: {}'.format(args))
@contextmanager
def make_certificate_useable():
KEYCHAIN = tempfile.NamedTemporaryFile(suffix='.keychain', dir=os.path.expanduser('~'), delete=False).name
os.remove(KEYCHAIN)
KEYCHAIN_PASSWORD = '{}'.format(uuid4())
# Create temp keychain
run('security create-keychain -p "{}" "{}"'.format(KEYCHAIN_PASSWORD, KEYCHAIN))
# Append temp keychain to the user domain
raw = subprocess.check_output('security list-keychains -d user'.split()).decode('utf-8')
existing_keychain = raw.replace('"', '').strip()
run('security list-keychains -d user -s "{}" "{}"'.format(KEYCHAIN, existing_keychain))
try:
# Remove relock timeout
run('security set-keychain-settings "{}"'.format(KEYCHAIN))
# Unlock keychain
run('security unlock-keychain -p "{}" "{}"'.format(KEYCHAIN_PASSWORD, KEYCHAIN))
# Add certificate to keychain
with open(CODESIGN_CREDS, 'r') as f:
cert_pass = f.read().strip()
# Add certificate to keychain and allow codesign to use it
# Use -A instead of -T /usr/bin/codesign to allow all apps to use it
run('security import {} -k "{}" -P "{}" -T "/usr/bin/codesign"'.format(
CODESIGN_CERT, KEYCHAIN, cert_pass))
raw = subprocess.check_output([
'security', 'find-identity', '-v', '-p', 'codesigning', KEYCHAIN]).decode('utf-8')
cert_id = re.search(r'"([^"]+)"', raw).group(1)
# Enable codesigning from a non user interactive shell
run('security set-key-partition-list -S apple-tool:,apple: -s -k "{}" -D "{}" -t private "{}"'.format(
KEYCHAIN_PASSWORD, cert_id, KEYCHAIN))
yield
finally:
# Delete temporary keychain
run('security delete-keychain "{}"'.format(KEYCHAIN))
def codesign(items):
if isinstance(items, str):
items = [items]
# If you get errors while codesigning that look like "A timestamp was
# expected but not found" it means that codesign failed to contact Apple's time
# servers, probably due to network congestion
#
# --options=runtime enables the Hardened Runtime
subprocess.check_call([
'codesign', '--options=runtime', '--entitlements=' + path_to_entitlements,
'--timestamp', '-s', 'Kovid Goyal'
] + list(items))
def notarize_app(app_path):
# See
# https://developer.apple.com/documentation/xcode/notarizing_your_app_before_distribution/customizing_the_notarization_workflow?language=objc
# and
# https://developer.apple.com/documentation/xcode/notarizing_your_app_before_distribution/resolving_common_notarization_issues?language=objc
with open(APPLE_ID) as f:
un, pw = f.read().strip().split(':')
with open(os.path.join(app_path, 'Contents', 'Info.plist'), 'rb') as f:
primary_bundle_id = plistlib.load(f)['CFBundleIdentifier']
zip_path = os.path.join(os.path.dirname(app_path), 'calibre.zip')
print('Creating zip file for notarization')
with timeit() as times:
run('ditto', '-c', '-k', '--zlibCompressionLevel', '9', '--keepParent', app_path, zip_path)
print('ZIP file of {} MB created in {} minutes and {} seconds'.format(os.path.getsize(zip_path) // 1024**2, *times))
def altool(*args):
args = ['xcrun', 'altool'] + list(args) + ['--username', un, '--password', pw]
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
stdout = stdout.decode('utf-8')
stderr = stderr.decode('utf-8')
output = stdout + '\n' + stderr
print(output)
if p.wait() != 0:
print('The command {} failed with error code: {}'.format(args, p.returncode))
try:
run_shell()
finally:
raise SystemExit(1)
return output
print('Submitting for notarization')
with timeit() as times:
try:
stdout = altool('--notarize-app', '-f', zip_path, '--primary-bundle-id', primary_bundle_id)
finally:
os.remove(zip_path)
request_id = re.search(r'RequestUUID = (\S+)', stdout).group(1)
status = 'in progress'
print('Submission done in {} minutes and {} seconds'.format(*times))
print('Waiting for notarization')
with timeit() as times:
start_time = time.monotonic()
while status == 'in progress':
time.sleep(30)
print('Checking if notarization is complete, time elapsed: {:.1f} seconds'.format(time.monotonic() - start_time))
stdout = altool('--notarization-info', request_id)
status = re.search(r'Status\s*:\s+(.+)', stdout).group(1).strip()
print('Notarization done in {} minutes and {} seconds'.format(*times))
if status.lower() != 'success':
log_url = re.search(r'LogFileURL\s*:\s+(.+)', stdout).group(1).strip()
if log_url != '(null)':
log = json.loads(urlopen(log_url).read())
pprint(log)
raise SystemExit('Notarization failed, see JSON log above')
with timeit() as times:
print('Stapling notarization ticket')
run('xcrun', 'stapler', 'staple', '-v', app_path)
run('xcrun', 'stapler', 'validate', '-v', app_path)
run('spctl', '--verbose=4', '--assess', '--type', 'execute', app_path)
print('Stapling took {} minutes and {} seconds'.format(*times))
def files_in(folder):
for record in os.walk(folder):
for f in record[-1]:
yield os.path.join(record[0], f)
def expand_dirs(items, exclude=lambda x: x.endswith('.so')):
items = set(items)
dirs = set(x for x in items if os.path.isdir(x))
items.difference_update(dirs)
for x in dirs:
items.update({y for y in files_in(x) if not exclude(y)})
return items
def get_executable(info_path):
with open(info_path, 'rb') as f:
return plistlib.load(f)['CFBundleExecutable']
def create_entitlements_file():
ans = {
# MAP_JIT is used by libpcre which is bundled with Qt
'com.apple.security.cs.allow-jit': True,
# v8 and therefore WebEngine need this as they dont use MAP_JIT
'com.apple.security.cs.allow-unsigned-executable-memory': True,
# calibre itself does not use DYLD env vars, but dont know about its
# dependencies.
'com.apple.security.cs.allow-dyld-environment-variables': True,
# Allow loading of unsigned plugins or frameworks
# 'com.apple.security.cs.disable-library-validation': True,
}
with open(path_to_entitlements, 'wb') as f:
f.write(plistlib.dumps(ans))
def find_sub_apps(contents_dir='.'):
for app in glob(os.path.join(contents_dir, '*.app')):
cdir = os.path.join(app, 'Contents')
for sapp in find_sub_apps(cdir):
yield sapp
yield app
def sign_MacOS(contents_dir='.'):
# Sign everything in MacOS except the main executable
# which will be signed automatically by codesign when
# signing the app bundles
with current_dir(os.path.join(contents_dir, 'MacOS')):
exe = get_executable('../Info.plist')
items = {x for x in os.listdir('.') if x != exe and not os.path.islink(x)}
if items:
codesign(items)
def do_sign_app(appdir):
appdir = os.path.abspath(appdir)
with current_dir(os.path.join(appdir, 'Contents')):
sign_MacOS()
# Sign the sub application bundles
sub_apps = list(find_sub_apps())
sub_apps.append('Frameworks/QtWebEngineCore.framework/Versions/Current/Helpers/QtWebEngineProcess.app')
for sa in sub_apps:
sign_MacOS(os.path.join(sa, 'Contents'))
codesign(sub_apps)
# Sign all .so files
so_files = {x for x in files_in('.') if x.endswith('.so')}
codesign(so_files)
# Sign everything in PlugIns
with current_dir('PlugIns'):
items = set(os.listdir('.'))
codesign(expand_dirs(items))
# Sign everything else in Frameworks
with current_dir('Frameworks'):
fw = set(glob('*.framework'))
codesign(fw)
items = set(os.listdir('.')) - fw
codesign(expand_dirs(items))
# Now sign the main app
codesign(appdir)
# Verify the signature
run('codesign', '-vvv', '--deep', '--strict', appdir)
run('spctl', '--verbose=4', '--assess', '--type', 'execute', appdir)
return 0
def sign_app(appdir, notarize):
create_entitlements_file()
with make_certificate_useable():
do_sign_app(appdir)
if notarize:
notarize_app(appdir)

187
bypy/macos/site.py Normal file
View File

@ -0,0 +1,187 @@
"""
Append module search paths for third-party packages to sys.path.
This is stripped down and customized for use in py2app applications
"""
import sys
import os
def makepath(*paths):
dir = os.path.abspath(os.path.join(*paths))
return dir, os.path.normcase(dir)
def abs__file__():
"""Set all module __file__ attribute to an absolute path"""
for m in sys.modules.values():
if hasattr(m, '__loader__'):
continue # don't mess with a PEP 302-supplied __file__
try:
m.__file__ = os.path.abspath(m.__file__)
except AttributeError:
continue
# This ensures that the initial path provided by the interpreter contains
# only absolute pathnames, even if we're running from the build directory.
L = []
_dirs_in_sys_path = {}
dir = dircase = None # sys.path may be empty at this point
for dir in sys.path:
# Filter out duplicate paths (on case-insensitive file systems also
# if they only differ in case); turn relative paths into absolute
# paths.
dir, dircase = makepath(dir)
if dircase not in _dirs_in_sys_path:
L.append(dir)
_dirs_in_sys_path[dircase] = 1
sys.path[:] = L
del dir, dircase, L
_dirs_in_sys_path = None
def _init_pathinfo():
global _dirs_in_sys_path
_dirs_in_sys_path = d = {}
for dir in sys.path:
if dir and not os.path.isdir(dir):
continue
dir, dircase = makepath(dir)
d[dircase] = 1
def addsitedir(sitedir):
global _dirs_in_sys_path
if _dirs_in_sys_path is None:
_init_pathinfo()
reset = 1
else:
reset = 0
sitedir, sitedircase = makepath(sitedir)
if sitedircase not in _dirs_in_sys_path:
sys.path.append(sitedir) # Add path component
try:
names = os.listdir(sitedir)
except os.error:
return
names.sort()
for name in names:
if name[-4:] == os.extsep + "pth":
addpackage(sitedir, name)
if reset:
_dirs_in_sys_path = None
def addpackage(sitedir, name):
global _dirs_in_sys_path
if _dirs_in_sys_path is None:
_init_pathinfo()
reset = 1
else:
reset = 0
fullname = os.path.join(sitedir, name)
try:
f = open(fullname)
except IOError:
return
while True:
dir = f.readline()
if not dir:
break
if dir[0] == '#':
continue
if dir.startswith("import"):
exec dir
continue
if dir[-1] == '\n':
dir = dir[:-1]
dir, dircase = makepath(sitedir, dir)
if dircase not in _dirs_in_sys_path and os.path.exists(dir):
sys.path.append(dir)
_dirs_in_sys_path[dircase] = 1
if reset:
_dirs_in_sys_path = None
# Remove sys.setdefaultencoding() so that users cannot change the
# encoding after initialization. The test for presence is needed when
# this module is run as a script, because this code is executed twice.
#
if hasattr(sys, "setdefaultencoding"):
sys.setdefaultencoding('utf-8')
del sys.setdefaultencoding
def run_entry_point():
bname, mod, func = sys.calibre_basename, sys.calibre_module, sys.calibre_function
sys.argv[0] = bname
pmod = __import__(mod, fromlist=[1], level=0)
return getattr(pmod, func)()
def read_user_env_vars():
try:
with open(os.path.expanduser('~/Library/Preferences/calibre/macos-env.txt'), 'rb') as f:
raw = f.read().decode('utf-8', 'replace')
except EnvironmentError as err:
return
for line in raw.splitlines():
if line.startswith('#'):
continue
parts = line.split('=', 1)
if len(parts) == 2:
key, val = parts
os.environ[key] = os.path.expandvars(os.path.expanduser(val))
def add_calibre_vars(base):
sys.frameworks_dir = os.path.join(os.path.dirname(base), 'Frameworks')
sys.resources_location = os.path.abspath(os.path.join(base, 'resources'))
sys.extensions_location = os.path.join(sys.frameworks_dir, 'plugins')
sys.binaries_path = os.path.join(os.path.dirname(base), 'MacOS')
try:
read_user_env_vars()
except Exception as err:
try:
sys.stderr.write('Failed to read user env vars with error: {}\n'.format(err))
sys.stderr.flush()
except Exception:
pass
dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
if dv and os.path.exists(dv):
sys.path.insert(0, os.path.abspath(dv))
def nuke_stdout():
# Redirect stdout, stdin and stderr to /dev/null
from calibre.constants import plugins
plugins['speedup'][0].detach(os.devnull)
def main():
global __file__
# Needed on OS X <= 10.8, which passes -psn_... as a command line arg when
# starting via launch services
for arg in tuple(sys.argv[1:]):
if arg.startswith('-psn_'):
sys.argv.remove(arg)
base = sys.resourcepath
sys.frozen = 'macosx_app'
sys.new_app_bundle = True
abs__file__()
add_calibre_vars(base)
addsitedir(sys.site_packages)
if sys.calibre_is_gui_app and not (
sys.stdout.isatty() or sys.stderr.isatty() or sys.stdin.isatty()
):
nuke_stdout()
return run_entry_point()

213
bypy/macos/util.c Normal file
View File

@ -0,0 +1,213 @@
#include "util.h"
#include <stdlib.h>
#include <strings.h>
#include <CoreFoundation/CoreFoundation.h>
#include <mach-o/dyld.h>
#include <Python.h>
#define EXPORT __attribute__((visibility("default")))
static const char *ERR_OOM = "Out of memory";
static int
report_error(const char *msg) {
fprintf(stderr, "%s\n", msg);
fflush(stderr);
return -1;
}
static int
report_code(const char *preamble, const char* msg, int code) {
fprintf(stderr, "%s: %s\n", preamble, msg);
fflush(stderr);
return code;
}
#define EXE "@executable_path/.."
static void
set_env_vars(const char **ENV_VARS, const char **ENV_VAR_VALS, const char* exe_path) {
int i = 0;
char buf[3*PATH_MAX];
const char *env_var, *val;
while(1) {
env_var = ENV_VARS[i];
if (env_var == NULL) break;
val = ENV_VAR_VALS[i++];
if (strstr(val, EXE) == val && strlen(val) >= strlen(EXE)+1) {
strncpy(buf, exe_path, 3*PATH_MAX-150);
strncpy(buf+strlen(exe_path), val+strlen(EXE), 150);
setenv(env_var, buf, 1);
} else
setenv(env_var, val, 1);
}
return;
}
void initialize_interpreter(const char **ENV_VARS, const char **ENV_VAR_VALS,
char *PROGRAM, const char *MODULE, const char *FUNCTION, const char *PYVER, int IS_GUI,
const char* exe_path, const char *rpath, int argc, char* const *argv) {
PyObject *pargv, *v;
int i;
Py_OptimizeFlag = 2;
Py_NoSiteFlag = 1;
Py_DontWriteBytecodeFlag = 1;
Py_IgnoreEnvironmentFlag = 1;
Py_NoUserSiteDirectory = 1;
Py_HashRandomizationFlag = 1;
//Py_VerboseFlag = 1;
//Py_DebugFlag = 1;
Py_SetProgramName(PROGRAM);
char pyhome[1000];
snprintf(pyhome, 1000, "%s/Python", rpath);
Py_SetPythonHome(pyhome);
set_env_vars(ENV_VARS, ENV_VAR_VALS, exe_path);
//printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath());
Py_Initialize();
char *dummy_argv[1] = {""};
PySys_SetArgv(1, dummy_argv);
//printf("Path after Py_Initialize(): %s\r\n\n", Py_GetPath());
char path[3000];
snprintf(path, 3000, "%s/lib/python%s:%s/lib/python%s/lib-dynload:%s/site-packages", pyhome, PYVER, pyhome, PYVER, pyhome);
PySys_SetPath(path);
//printf("Path set by me: %s\r\n\n", path);
PySys_SetObject("calibre_basename", PyBytes_FromString(PROGRAM));
PySys_SetObject("calibre_module", PyBytes_FromString(MODULE));
PySys_SetObject("calibre_function", PyBytes_FromString(FUNCTION));
PySys_SetObject("calibre_is_gui_app", ((IS_GUI) ? Py_True : Py_False));
PySys_SetObject("resourcepath", PyBytes_FromString(rpath));
snprintf(path, 3000, "%s/site-packages", pyhome);
PySys_SetObject("site_packages", PyBytes_FromString(pyhome));
pargv = PyList_New(argc);
if (pargv == NULL) exit(report_error(ERR_OOM));
for (i = 0; i < argc; i++) {
v = PyBytes_FromString(argv[i]);
if (v == NULL) exit(report_error(ERR_OOM));
PyList_SetItem(pargv, i, v);
}
PySys_SetObject("argv", pargv);
}
int pyobject_to_int(PyObject *res) {
int ret; PyObject *tmp;
tmp = PyNumber_Int(res);
if (tmp == NULL) ret = (PyObject_IsTrue(res)) ? 1 : 0;
else ret = (int)PyInt_AS_LONG(tmp);
return ret;
}
int handle_sysexit(PyObject *e) {
PyObject *code;
code = PyObject_GetAttrString(e, "code");
if (!code) return 0;
if (!PyInt_Check(code)) {
PyObject_Print(code, stderr, Py_PRINT_RAW);
fflush(stderr);
}
return pyobject_to_int(code);
}
int calibre_show_python_error(const char *preamble, int code) {
PyObject *exc, *val, *tb, *str;
int ret, issysexit = 0; char *i;
if (!PyErr_Occurred()) return code;
issysexit = PyErr_ExceptionMatches(PyExc_SystemExit);
PyErr_Fetch(&exc, &val, &tb);
if (exc != NULL) {
PyErr_NormalizeException(&exc, &val, &tb);
if (issysexit) {
return (val) ? handle_sysexit(val) : 0;
}
if (val != NULL) {
str = PyObject_Unicode(val);
if (str == NULL) {
PyErr_Clear();
str = PyObject_Str(val);
}
i = PyString_AsString(str);
ret = report_code(preamble, (i==NULL)?ERR_OOM:i, code);
if (tb != NULL) {
PyErr_Restore(exc, val, tb);
PyErr_Print();
}
return ret;
}
}
return report_code(preamble, "", code);
}
EXPORT
int
run(const char **ENV_VARS, const char **ENV_VAR_VALS, char *PROGRAM,
const char *MODULE, const char *FUNCTION, const char *PYVER,
int IS_GUI, int argc, char * const *argv, const char **envp, char *full_exe_path) {
char *t = NULL;
int ret = 0, i;
PyObject *site, *mainf, *res;
uint32_t buf_size = PATH_MAX+1;
for (i = 0; i < 3; i++) {
t = rindex(full_exe_path, '/');
if (t == NULL) return report_error("Failed to determine bundle path.");
*t = '\0';
}
if (strstr(full_exe_path, "/calibre.app/Contents/") != NULL) {
// We are one of the duplicate executables created to workaround codesign's limitations
for (i = 0; i < 2; i++) {
t = rindex(full_exe_path, '/');
if (t == NULL) return report_error("Failed to resolve bundle path in dummy executable");
*t = '\0';
}
}
char rpath[PATH_MAX+1], exe_path[PATH_MAX+1];
snprintf(exe_path, PATH_MAX+1, "%s/Contents", full_exe_path);
snprintf(rpath, PATH_MAX+1, "%s/Resources", exe_path);
initialize_interpreter(ENV_VARS, ENV_VAR_VALS, PROGRAM, MODULE, FUNCTION, PYVER, IS_GUI,
exe_path, rpath, argc, argv);
site = PyImport_ImportModule("site");
if (site == NULL)
ret = calibre_show_python_error("Failed to import site module", -1);
else {
Py_XINCREF(site);
mainf = PyObject_GetAttrString(site, "main");
if (mainf == NULL || !PyCallable_Check(mainf))
ret = calibre_show_python_error("site module has no main function", -1);
else {
Py_XINCREF(mainf);
res = PyObject_CallObject(mainf, NULL);
if (res == NULL)
ret = calibre_show_python_error("Python function terminated unexpectedly", -1);
else {
}
}
}
PyErr_Clear();
Py_Finalize();
//printf("11111 Returning: %d\r\n", ret);
return ret;
}

5
bypy/macos/util.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
int run(const char **ENV_VARS, const char **ENV_VAR_VALS, char *PROGRAM,
const char *MODULE, const char *FUNCTION, const char *PYVER, int IS_GUI,
int argc, char *const *argv, const char **envp, char *full_exe_path);

1
bypy/rsync.conf Normal file
View File

@ -0,0 +1 @@
to_vm_excludes '/imgsrc /build /dist /manual /format_docs /translations /.build-cache /tags /Changelog* *.so *.pyd'

824
bypy/sources.json Normal file
View File

@ -0,0 +1,824 @@
[
{
"name": "nasm",
"os": "macos,windows",
"unix": {
"filename": "nasm-2.14.02.tar.xz",
"hash": "sha256:e24ade3e928f7253aa8c14aa44726d1edf3f98643f87c9d72ec1df44b26be8f5",
"urls": ["https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/{filename}"]
}
},
{
"name": "cmake",
"os": "macos",
"unix": {
"filename": "cmake-3.14.4.tar.gz",
"hash": "sha256:00b4dc9b0066079d10f16eed32ec592963a44e7967371d2f5077fd1670ff36d9",
"urls": ["https://github.com/Kitware/CMake/releases/download/v3.14.4/{filename}"]
}
},
{
"name": "autoconf",
"os": "macos",
"unix": {
"filename": "autoconf-2.69.tar.xz",
"hash": "sha256:64ebcec9f8ac5b2487125a86a7760d2591ac9e1d3dbd59489633f9de62a57684",
"urls": ["ftp://ftp.gnu.org/gnu/autoconf/{filename}"]
}
},
{
"name": "automake",
"os": "macos",
"unix": {
"filename": "automake-1.16.tar.xz",
"hash": "sha256:f98f2d97b11851cbe7c2d4b4eaef498ae9d17a3c2ef1401609b7b4ca66655b8a",
"urls": ["ftp://ftp.gnu.org/gnu/automake/{filename}"]
}
},
{
"name": "libtool",
"os": "macos",
"unix": {
"filename": "libtool-2.4.6.tar.xz",
"hash": "sha256:7c87a8c2c8c0fc9cd5019e402bed4292462d00a718a7cd5f11218153bf28b26f",
"urls": ["ftp://ftp.gnu.org/gnu/libtool/{filename}"]
}
},
{
"name": "easylzma",
"os": "windows",
"windows": {
"filename": "easylzma-1753f61f673abdebc08fcf4a37eedd6da8a67ba1.tar.gz",
"hash": "sha256:7664240898fe09bce8b39cd428407dd24ac3b87200e6b40d4007c78f2c725254",
"urls": ["github:lloyd/easylzma"]
}
},
{
"name": "zlib",
"unix": {
"filename": "zlib-1.2.11.tar.xz",
"hash": "sha256:4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066",
"urls": ["https://zlib.net/{filename}"]
}
},
{
"name": "bzip2",
"os": "linux",
"unix": {
"filename": "bzip2-1.0.6.tar.gz",
"hash": "md5:00b516f4704d4a7cb50a1d97e6e8e15b",
"urls": ["https://sources.archlinux.org/other/packages/bzip2/{filename}"]
}
},
{
"name": "unrar",
"unix": {
"filename": "unrarsrc-5.9.1.tar.gz",
"hash": "sha256:0eb1d1b8e02102fccae775a6d6b79336b69e2cf90e2045de92594dcfb58de100",
"urls": ["https://www.rarlab.com/rar/{filename}"]
}
},
{
"name": "expat",
"unix": {
"filename": "expat-2.2.6.tar.bz2",
"hash": "sha256:17b43c2716d521369f82fc2dc70f359860e90fa440bea65b3b85f0b246ea81f2",
"urls": ["https://github.com/libexpat/libexpat/releases/download/R_2_2_6/{filename}"]
}
},
{
"name": "sqlite",
"unix": {
"filename": "sqlite-autoconf-3310100.tar.gz",
"hash": "sha1:0c30f5b22152a8166aa3bebb0f4bc1f3e9cc508b",
"urls": ["https://www.sqlite.org/2020/{filename}"]
}
},
{
"name": "libffi",
"os": "linux",
"unix": {
"filename": "libffi-3.2.1.tar.gz",
"hash": "sha1:280c265b789e041c02e5c97815793dfc283fb1e6",
"urls": ["ftp://sourceware.org/pub/libffi/{filename}"]
}
},
{
"name": "hyphen",
"unix": {
"filename": "hyphen-2.8.8.tar.gz",
"hash": "sha1:0556c392beb59433e577e3517575801212201df6",
"urls": ["https://downloads.sourceforge.net/hunspell/{filename}"]
}
},
{
"name": "openssl",
"unix": {
"filename": "openssl-1.0.2r.tar.gz",
"hash": "sha256:ae51d08bba8a83958e894946f15303ff894d75c2b8bbd44a852b64e3fe11d0d6",
"urls": ["https://www.openssl.org/source/{filename}"]
}
},
{
"name": "ncurses",
"os": "linux",
"unix": {
"filename": "ncurses-6.1.tar.gz",
"hash": "sha256:aa057eeeb4a14d470101eff4597d5833dcef5965331be3528c08d99cebaa0d17",
"urls": ["ftp://ftp.gnu.org/gnu/ncurses/{filename}"]
}
},
{
"name": "readline",
"os": "linux",
"unix": {
"filename": "readline-8.0.tar.gz",
"hash": "sha256:e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461",
"urls": ["http://ftp.gnu.org/gnu/readline/{filename}"]
}
},
{
"name": "python",
"unix": {
"filename": "Python-2.7.16.tar.xz",
"hash": "sha256:f222ef602647eecb6853681156d32de4450a2c39f4de93bd5b20235f2e660ed7",
"urls": ["https://www.python.org/ftp/python/2.7.16/{filename}"]
},
"windows": {
"filename":"python-584870604fd8524e17bc2c067595b0210411319e.tar.gz",
"hash":"sha256:4f1833cac526f209de5b428d517cbd7a7923f13b89ba056e239dd8aa15894b7d",
"urls":["github:kovidgoyal/cpython"]
}
},
{
"name": "icu",
"unix": {
"filename": "icu4c-64_2-src.tgz",
"hash": "sha256:627d5d8478e6d96fc8c90fed4851239079a561a6a8b9e48b0892f24e82d31d6c",
"urls": ["http://download.icu-project.org/files/icu4c/64.2/{filename}"]
},
"windows": {
"filename": "icu4c-64_2-src.zip",
"hash": "sha256:c8df046a9944003dae744197648e0fa6c745478b7d7b4e2b05f6a390868b5752",
"urls": ["http://download.icu-project.org/files/icu4c/64.2/{filename}"]
}
},
{
"name": "libjpeg",
"unix": {
"filename": "libjpeg-turbo-2.0.2.tar.gz",
"hash": "sha256:acb8599fe5399af114287ee5907aea4456f8f2c1cc96d26c28aebfdf5ee82fed",
"urls": ["http://downloads.sourceforge.net/project/libjpeg-turbo/2.0.2/{filename}"]
}
},
{
"name": "libpng",
"unix": {
"filename": "libpng-1.6.37.tar.xz",
"hash": "sha256:505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca",
"urls": ["http://downloads.sourceforge.net/sourceforge/libpng/{filename}"]
}
},
{
"name": "libwebp",
"unix": {
"filename": "libwebp-1.0.2.tar.gz",
"hash": "sha256:3d47b48c40ed6476e8047b2ddb81d93835e0ca1b8d3e8c679afbb3004dd564b1",
"urls": ["http://downloads.webmproject.org/releases/webp/{filename}"]
}
},
{
"name": "jxrlib",
"unix": {
"filename": "jxrlib-0.2.1.tar.gz",
"hash": "sha256:5ae964ae61f301f38a62b8e18eb8d2eee27eaf2b942477b033435ebf38fa4a19",
"urls": ["https://github.com/glencoesoftware/jxrlib/archive/v0.2.1.tar.gz"]
}
},
{
"name": "freetype",
"os": "macos,windows",
"unix": {
"filename": "freetype-2.10.0.tar.bz2",
"hash": "sha256:fccc62928c65192fff6c98847233b28eb7ce05f12d2fea3f6cc90e8b4e5fbe06",
"urls": ["https://download.savannah.gnu.org/releases/freetype/{filename}"]
}
},
{
"name": "fontconfig",
"os": "macos",
"unix": {
"filename": "fontconfig-2.13.1.tar.bz2",
"hash": "sha256:f655dd2a986d7aa97e052261b36aa67b0a64989496361eca8d604e6414006741",
"urls": ["https://www.fontconfig.org/release/{filename}"]
}
},
{
"name": "iconv",
"os": "macos, linux",
"unix": {
"filename": "libiconv-1.15.tar.gz",
"hash": "sha256:ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178",
"urls": ["https://ftp.gnu.org/pub/gnu/libiconv/{filename}"]
}
},
{
"name": "libxml2",
"unix": {
"filename": "libxml2-2.9.9.tar.gz",
"hash": "sha256:94fb70890143e3c6549f265cee93ec064c80a84c42ad0f23e85ee1fd6540a871",
"urls": ["ftp://xmlsoft.org/libxml2/{filename}"]
}
},
{
"name": "libxslt",
"unix": {
"filename": "libxslt-1.1.33.tar.gz",
"hash": "sha256:8e36605144409df979cab43d835002f63988f3dc94d5d3537c12796db90e38c8",
"urls": ["ftp://xmlsoft.org/libxml2/{filename}"]
}
},
{
"name": "chmlib",
"unix": {
"filename": "chmlib-0.40.tar.bz2",
"hash": "sha1:5231d7531e8808420d7f89fd1e4fdbac1ed7a167",
"urls": ["http://www.jedrea.com/chmlib/{filename}"]
}
},
{
"name": "optipng",
"unix": {
"filename": "optipng-0.7.7.tar.gz",
"hash": "sha256:4f32f233cef870b3f95d3ad6428bfe4224ef34908f1b42b0badf858216654452",
"urls": ["https://downloads.sourceforge.net/sourceforge/optipng/{filename}"]
}
},
{
"name": "mozjpeg",
"unix": {
"filename": "mozjpeg-3.3.1.tar.gz",
"hash": "sha256:aebbea60ea038a84a2d1ed3de38fdbca34027e2e54ee2b7d08a97578be72599d",
"urls": ["https://github.com/mozilla/mozjpeg/archive/v3.3.1.tar.gz"]
}
},
{
"name": "libusb",
"os": "macos, linux",
"unix": {
"filename": "libusb-1.0.22.tar.bz2",
"hash": "sha256:75aeb9d59a4fdb800d329a545c2e6799f732362193b465ea198f2aa275518157",
"urls": ["https://downloads.sourceforge.net/libusb/{filename}"]
}
},
{
"name": "libmtp",
"os": "macos, linux",
"unix": {
"filename": "libmtp-1.1.16.tar.gz",
"hash": "sha256:5b68f9dd1ed38de558de687f40e255a39e4d5e32ef3de601f0ac19dd5682bba0",
"urls": ["https://downloads.sourceforge.net/libmtp/{filename}"]
}
},
{
"name": "openjpeg",
"unix": {
"filename": "openjpeg-2.3.1.tar.gz",
"hash": "sha256:63f5a4713ecafc86de51bfad89cc07bb788e9bba24ebbf0c4ca637621aadb6a9",
"urls": ["https://github.com/uclouvain/openjpeg/archive/v2.3.1/{filename}"]
}
},
{
"name": "poppler",
"unix": {
"filename": "poppler-0.76.1.tar.xz",
"hash": "sha256:e62cd4053f851eecc4a6aa2b81d739fbab1d67b3c60b31ebac7049483cc617b1",
"urls": ["https://poppler.freedesktop.org/{filename}"]
}
},
{
"name": "podofo",
"unix": {
"filename": "podofo-0.9.6.tar.gz",
"hash": "md5:46336fc4c4ce4be814bb5fbb4d918334",
"urls": ["https://downloads.sourceforge.net/podofo/{filename}"]
}
},
{
"name": "libgpg-error",
"os": "linux",
"unix": {
"filename": "libgpg-error-1.36.tar.bz2",
"hash": "sha256:babd98437208c163175c29453f8681094bcaf92968a15cafb1a276076b33c97c",
"urls": ["ftp://ftp.gnupg.org/gcrypt/libgpg-error/{filename}"]
}
},
{
"name": "libgcrypt",
"os": "linux",
"unix": {
"filename": "libgcrypt-1.8.4.tar.bz2",
"hash": "sha256:f638143a0672628fde0cad745e9b14deb85dffb175709cacc1f4fe24b93f2227",
"urls": ["ftp://ftp.gnupg.org/gcrypt/libgcrypt/{filename}"]
}
},
{
"name": "glib",
"os": "linux",
"unix": {
"filename": "glib-2.60.1.tar.xz",
"hash": "sha256:89f884f5d5c6126140ec868cef184c42ce72902c13cd08f36e660371779b5560",
"urls": ["http://ftp.gnome.org/pub/GNOME/sources/glib/2.60/{filename}"]
}
},
{
"name": "dbus",
"os": "linux",
"unix": {
"filename": "dbus-1.12.12.tar.gz",
"hash": "sha256:9546f226011a1e5d9d77245fe5549ef25af4694053189d624d0d6ac127ecf5f8",
"urls": ["https://dbus.freedesktop.org/releases/dbus/{filename}"]
}
},
{
"name": "dbusglib",
"os": "linux",
"unix": {
"filename": "dbus-glib-0.110.tar.gz",
"hash": "sha256:7ce4760cf66c69148f6bd6c92feaabb8812dee30846b24cd0f7395c436d7e825",
"urls": ["https://dbus.freedesktop.org/releases/dbus-glib/{filename}"]
}
},
{
"name": "gnuwin32",
"os": "windows",
"windows": {
"filename": "gnuwin32.zip",
"hash": "sha256:4a9dc893cc0a1695a16102a42ef47ef2e228652891f4afea67fadd452b63656b",
"urls": ["http://download.qt.io/development_releases/gnuwin32/{filename}"]
}
},
{
"name": "hunspell",
"unix": {
"filename": "hunspell-1.7.0.tar.gz",
"hash": "sha256:57be4e03ae9dd62c3471f667a0d81a14513e314d4d92081292b90435944ff951",
"urls": ["https://github.com/hunspell/hunspell/files/2573619/{filename}"]
},
"windows": {
"filename": "hunspell-1.7.0.zip",
"hash": "sha256:7089cc01ffd9122c960e1f8c7930a75be989ca4e9468773cef1b0a655bfb4368",
"urls": ["https://github.com/hunspell/hunspell/archive/v1.7.0.zip"]
}
},
{
"name": "qt-base",
"version": "5.14.1",
"hashes": {
"unix": "sha256:d9d423a6e7bcf1055c0372fc029f14a6fe67dd62c67b83095cde68b60b762cf7"
}
},
{
"name": "qt-svg",
"hashes": {
"unix": "sha256:8540a57312f815f81a45b891b49959d776727fde17579bb6bf1a537996bc9359"
}
},
{
"name": "qt-declarative",
"hashes": {
"unix": "sha256:762fe495d2f97fd70f06dc7d3929506ea3b5e3151ad813e0629209b7bc504c8a"
}
},
{
"name": "qt-imageformats",
"hashes": {
"unix": "sha256:b8b177ea68df3a99f45740cb3193e3b38738c5e2b272028445bd31a4305c8e5e"
}
},
{
"name": "qt-webchannel",
"hashes": {
"unix": "sha256:3af5262fde14c7dfe7bcc12d5796a482837bd09f0878851fd8de5db0b1985e6a"
}
},
{
"name": "qt-location",
"hashes": {
"unix": "sha256:a0dd1712a5b7a0425b57d17318294b6f7e968c4b81d52048696d029b04d2f12f"
}
},
{
"name": "qt-x11extras",
"os": "linux",
"hashes": {
"unix": "sha256:b268907deb06570671c1f584feb1508e7fded129209a268183decc122bfac181"
}
},
{
"name": "qt-wayland",
"os": "linux",
"hashes": {
"unix": "sha256:2a03b9f554e88c5824ef237c814b3dd45844c022e97be0e091f4a502ca4c9520"
}
},
{
"name": "qt-sensors",
"hashes": {
"unix": "sha256:eda3862cf079ac2357553be4faaae0136aa017e954506ca0c4239995b5be214c"
}
},
{
"name": "qt-macextras",
"os": "macos",
"hashes": {
"unix": "sha256:8c263fdba519d7e04bc64767883283eedede0752aa47cc440670129725696e29"
}
},
{
"name": "qt-winextras",
"os": "windows",
"hashes": {
"unix": "sha256:222b888b89a8fb02948faf985e8614ac543603a000c1cf2e7489f8bf15ccc3cc"
}
},
{
"name": "qt-webengine",
"hashes": {
"unix": "sha256:4ec77040a876a83aa2a833ebfe7b3e88dcc167ceb317095eb226a0b8d455e887"
}
},
{
"name": "setuptools",
"unix": {
"filename": "setuptools-41.0.1.zip",
"hash": "sha256:a222d126f5471598053c9a77f4b5d4f26eaa1f150ad6e01dcf1a42e185d05613",
"urls": ["pypi"]
}
},
{
"name": "six",
"unix": {
"filename": "six-1.12.0.tar.gz",
"hash": "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73",
"urls": ["pypi"]
}
},
{
"name": "pywin32",
"os": "windows",
"python": 2,
"windows": {
"filename":"pywin32-224.zip",
"hash":"sha256:fa01a3b9f5e6afd0412013b216d40120b92bbc575dbb3d1a0afb45d8bc1c88d8",
"urls":["https://github.com/mhammond/pywin32/archive/b224.zip"]
}
},
{
"name": "unrardll",
"unix": {
"filename": "unrardll-0.1.3.tar.gz",
"hash": "sha256:5f214ab1ec24208c6ee353f2d836e536968d5379b7140129f04aa3a52bc56a5e",
"urls": ["pypi"]
}
},
{
"name": "lxml",
"unix": {
"filename": "lxml-4.3.3.tar.gz",
"hash": "sha256:4a03dd682f8e35a10234904e0b9508d705ff98cf962c5851ed052e9340df3d90",
"urls": ["pypi"]
}
},
{
"name": "html5-parser",
"unix": {
"filename": "html5-parser-0.4.9.tar.gz",
"hash": "sha256:25fe8f6848cbc15187f6748c0695df32bcf1b37df6420b6a01b4ebe1ec1ed48f",
"urls": ["pypi"]
}
},
{
"name": "css-parser",
"unix": {
"filename": "css-parser-1.0.4.tar.gz",
"hash": "sha256:c7ab355512ae51334ba6791a7e4d553f87bef17ba2026f1cc9bf3b17a7779d44",
"urls": ["pypi"]
}
},
{
"name": "dateutil",
"unix": {
"filename": "python-dateutil-2.8.0.tar.gz",
"hash": "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e",
"urls": ["pypi"]
}
},
{
"name": "dbuspython",
"python": 2,
"os": "linux",
"unix": {
"filename": "dbus-python-1.2.8.tar.gz",
"hash": "sha256:abf12bbb765e300bf8e2a1b2f32f85949eab06998dbda127952c31cb63957b6f",
"urls": ["https://dbus.freedesktop.org/releases/dbus-python/{filename}"]
}
},
{
"name": "dnspython",
"unix": {
"filename": "dnspython-1.16.0.zip",
"hash": "sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
"urls": ["pypi"]
}
},
{
"name": "mechanize",
"unix": {
"filename": "mechanize-0.4.3.tar.gz",
"hash": "sha256:d7d7068be5e1b3069575c98c870aaa96dd26603fe8c8697b470e2f65259fddbf",
"urls": ["pypi"]
}
},
{
"name": "feedparser",
"unix": {
"filename": "feedparser-5.2.1.tar.bz2",
"hash": "sha256:ce875495c90ebd74b179855449040003a1beb40cd13d5f037a0654251e260b02",
"urls": ["pypi"]
}
},
{
"name": "markdown",
"unix": {
"filename": "Markdown-3.1.tar.gz",
"hash": "sha256:fc4a6f69a656b8d858d7503bda633f4dd63c2d70cf80abdc6eafa64c4ae8c250",
"urls": ["pypi"]
}
},
{
"name": "html2text",
"unix": {
"filename": "html2text-2018.1.9.tar.gz",
"hash": "sha256:627514fb30e7566b37be6900df26c2c78a030cc9e6211bda604d8181233bcdd4",
"urls": ["pypi"]
}
},
{
"name": "soupsieve",
"unix": {
"filename": "soupsieve-1.9.1.tar.gz",
"hash": "sha256:b20eff5e564529711544066d7dc0f7661df41232ae263619dede5059799cdfca",
"urls": ["pypi"]
}
},
{
"name": "beautifulsoup4",
"unix": {
"filename": "beautifulsoup4-4.7.1.tar.gz",
"hash": "sha256:945065979fb8529dd2f37dbb58f00b661bdbcbebf954f93b32fdf5263ef35348",
"urls": ["pypi"]
}
},
{
"name": "regex",
"unix": {
"filename": "regex-2019.04.14.tar.gz",
"hash": "sha256:d56ce4c7b1a189094b9bee3b81c4aeb3f1ba3e375e91627ec8561b6ab483d0a8",
"urls": ["pypi"]
}
},
{
"name": "chardet",
"unix": {
"filename": "chardet-3.0.4.tar.gz",
"hash": "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"urls": ["pypi"]
}
},
{
"name": "msgpack",
"unix": {
"filename": "msgpack-0.6.1.tar.gz",
"hash": "sha256:4008c72f5ef2b7936447dcb83db41d97e9791c83221be13d5e19db0796df1972",
"urls": ["pypi"]
}
},
{
"name": "pygments",
"unix": {
"filename": "Pygments-2.3.1.tar.gz",
"hash": "sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a",
"urls": ["pypi"]
}
},
{
"name": "pycrypto",
"unix": {
"filename": "pycrypto-2.6.1.tar.gz",
"hash": "sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c",
"urls": ["pypi"]
}
},
{
"name": "apsw",
"python": 2,
"unix": {
"filename": "apsw-3.30.1-r1.zip",
"hash": "sha256:b7be3dca5f95b88ff2285dbfb61e7449c8cb4214d3d18172ffdb163360c7aa2f",
"urls": ["https://github.com/rogerbinns/apsw/releases/download/3.30.1-r1/{filename}"]
}
},
{
"name": "webencodings",
"unix": {
"filename": "webencodings-0.5.1.tar.gz",
"hash": "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923",
"urls": ["pypi"]
}
},
{
"name": "html5lib",
"unix": {
"filename": "html5lib-1.0.1.tar.gz",
"hash": "sha256:66cb0dcfdbbc4f9c3ba1a63fdb511ffdbd4f513b2b6d81b80cd26ce6b3fb3736",
"urls": ["pypi"]
}
},
{
"name": "pillow",
"unix": {
"filename": "Pillow-6.0.0.tar.gz",
"hash": "sha256:809c0a2ce9032cbcd7b5313f71af4bdc5c8c771cb86eb7559afd954cab82ebb5",
"urls": ["pypi"]
}
},
{
"name": "netifaces",
"unix": {
"filename": "netifaces-0.10.9.tar.gz",
"hash": "sha256:2dee9ffdd16292878336a58d04a20f0ffe95555465fee7c9bd23b3490ef2abf3",
"urls": ["pypi"]
}
},
{
"name": "psutil",
"unix": {
"filename": "psutil-5.6.2.tar.gz",
"hash": "sha256:828e1c3ca6756c54ac00f1427fdac8b12e21b8a068c3bb9b631a1734cada25ed",
"urls": ["pypi"]
}
},
{
"name": "ifaddr",
"python": 3,
"unix": {
"filename": "ifaddr-0.1.6.tar.gz",
"hash": "sha256:c19c64882a7ad51a394451dabcbbed72e98b5625ec1e79789924d5ea3e3ecb93",
"urls": ["pypi"]
}
},
{
"name": "zeroconf",
"python": 3,
"unix": {
"filename": "zeroconf-0.21.3.tar.gz",
"hash": "sha256:5b52dfdf4e665d98a17bf9aa50dea7a8c98e25f972d9c1d7660e2b978a1f5713",
"urls": ["pypi"]
}
},
{
"name": "enum34",
"python": "<3",
"unix": {
"filename": "enum34-1.1.6.tar.gz",
"hash": "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1",
"urls": ["pypi"]
}
},
{
"name": "sip",
"unix": {
"filename": "sip-4.19.19.tar.gz",
"hash": "sha256:5436b61a78f48c7e8078e93a6b59453ad33780f80c644e5f3af39f94be1ede44",
"urls": ["https://www.riverbankcomputing.com/static/Downloads/sip/4.19.19/{filename}"]
}
},
{
"name": "pyqt",
"unix": {
"filename": "PyQt5_gpl-5.13.1.tar.gz",
"hash": "sha256:54b7f456341b89eeb3930e786837762ea67f235e886512496c4152ebe106d4af",
"urls": ["https://www.riverbankcomputing.com/static/Downloads/PyQt5/5.13.1/{filename}"]
}
},
{
"name": "pyqt-webengine",
"unix": {
"filename": "PyQtWebEngine_gpl-5.13.1.tar.gz",
"hash": "sha256:8d8c1262005d8465653a848bf67327fb338e0d3c2d26090a6f7eb071dbb42092",
"urls": ["https://www.riverbankcomputing.com/static/Downloads/PyQtWebEngine/5.13.1/{filename}"]
}
},
{
"name": "macfsevents",
"os": "macos",
"unix": {
"filename": "MacFSEvents-0.7.tar.gz",
"hash": "md5:089d52d40a088651302967b1d13c3825",
"urls": ["pypi"]
}
}
]

16
bypy/windows.conf Normal file
View File

@ -0,0 +1,16 @@
# Requires installation of Visual Studio 2017 Community Edition, WiX Toolset, Git, Ruby, Python 3.7 and Perl
# git.exe must be in PATH. Must have ~120GB available disk space and 8GB RAM
# Install certifi in python 3 with:
# py.exe -m pip install certifi
# Copy opengl32sw.dll from
# https://download.qt.io/development_releases/prebuilt/llvmpipe/windows/
# to C:/mesa/32 and C:/mesa/64
# Ensure the windwos sdk version at least 10.0.18362 or newer is installed, needed for
# qt-webengine-14.1
vm_name 'calibre-windows-build'
root 'C:/r'
python 'py.exe'
perl 'C:/Strawberry/perl/bin/perl.exe'
ruby 'C:/Ruby26-x64/bin/ruby.exe'
mesa 'C:/mesa'

4379
bypy/windows/XUnzip.cpp Normal file

File diff suppressed because it is too large Load Diff

382
bypy/windows/XUnzip.h Normal file
View File

@ -0,0 +1,382 @@
// XUnzip.h Version 1.3
//
// Authors: Mark Adler et al. (see below)
//
// Modified by: Lucian Wischik
// lu@wischik.com
//
// Version 1.0 - Turned C files into just a single CPP file
// - Made them compile cleanly as C++ files
// - Gave them simpler APIs
// - Added the ability to zip/unzip directly in memory without
// any intermediate files
//
// Modified by: Hans Dietrich
// hdietrich@gmail.com
//
///////////////////////////////////////////////////////////////////////////////
//
// Lucian Wischik's comments:
// --------------------------
// THIS FILE is almost entirely based upon code by info-zip.
// It has been modified by Lucian Wischik.
// The original code may be found at http://www.info-zip.org
// The original copyright text follows.
//
///////////////////////////////////////////////////////////////////////////////
//
// Original authors' comments:
// ---------------------------
// This is version 2002-Feb-16 of the Info-ZIP copyright and license. The
// definitive version of this document should be available at
// ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely.
//
// Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
//
// For the purposes of this copyright and license, "Info-ZIP" is defined as
// the following set of individuals:
//
// Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
// Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase,
// Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
// David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
// Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
// Kai Uwe Rommel, Steve Salisbury, Dave Smith, Christian Spieler,
// Antoine Verheijen, Paul von Behren, Rich Wales, Mike White
//
// This software is provided "as is", without warranty of any kind, express
// or implied. In no event shall Info-ZIP or its contributors be held liable
// for any direct, indirect, incidental, special or consequential damages
// arising out of the use of or inability to use this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. Redistributions of source code must retain the above copyright notice,
// definition, disclaimer, and this list of conditions.
//
// 2. Redistributions in binary form (compiled executables) must reproduce
// the above copyright notice, definition, disclaimer, and this list of
// conditions in documentation and/or other materials provided with the
// distribution. The sole exception to this condition is redistribution
// of a standard UnZipSFX binary as part of a self-extracting archive;
// that is permitted without inclusion of this license, as long as the
// normal UnZipSFX banner has not been removed from the binary or disabled.
//
// 3. Altered versions--including, but not limited to, ports to new
// operating systems, existing ports with new graphical interfaces, and
// dynamic, shared, or static library versions--must be plainly marked
// as such and must not be misrepresented as being the original source.
// Such altered versions also must not be misrepresented as being
// Info-ZIP releases--including, but not limited to, labeling of the
// altered versions with the names "Info-ZIP" (or any variation thereof,
// including, but not limited to, different capitalizations),
// "Pocket UnZip", "WiZ" or "MacZip" without the explicit permission of
// Info-ZIP. Such altered versions are further prohibited from
// misrepresentative use of the Zip-Bugs or Info-ZIP e-mail addresses or
// of the Info-ZIP URL(s).
//
// 4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip", "UnZip",
// "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and "MacZip" for its
// own source and binary releases.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef XUNZIP_H
#define XUNZIP_H
#ifndef XZIP_H
DECLARE_HANDLE(HZIP); // An HZIP identifies a zip file that has been opened
#endif
typedef DWORD ZRESULT;
// return codes from any of the zip functions. Listed later.
#define ZIP_HANDLE 1
#define ZIP_FILENAME 2
#define ZIP_MEMORY 3
typedef struct
{ int index; // index of this file within the zip
char name[MAX_PATH]; // filename within the zip
DWORD attr; // attributes, as in GetFileAttributes.
FILETIME atime,ctime,mtime;// access, create, modify filetimes
long comp_size; // sizes of item, compressed and uncompressed. These
long unc_size; // may be -1 if not yet known (e.g. being streamed in)
} ZIPENTRY;
typedef struct
{ int index; // index of this file within the zip
TCHAR name[MAX_PATH]; // filename within the zip
DWORD attr; // attributes, as in GetFileAttributes.
FILETIME atime,ctime,mtime;// access, create, modify filetimes
long comp_size; // sizes of item, compressed and uncompressed. These
long unc_size; // may be -1 if not yet known (e.g. being streamed in)
} ZIPENTRYW;
///////////////////////////////////////////////////////////////////////////////
//
// OpenZip()
//
// Purpose: Open an existing zip archive file
//
// Parameters: z - archive file name if flags is ZIP_FILENAME; for other
// uses see below
// len - for memory (ZIP_MEMORY) should be the buffer size;
// for other uses, should be 0
// flags - indicates usage, see below; for files, this will be
// ZIP_FILENAME
//
// Returns: HZIP - non-zero if zip archive opened ok, otherwise 0
//
HZIP OpenZip(void *z, unsigned int len, DWORD flags);
// OpenZip - opens a zip file and returns a handle with which you can
// subsequently examine its contents. You can open a zip file from:
// from a pipe: OpenZip(hpipe_read,0, ZIP_HANDLE);
// from a file (by handle): OpenZip(hfile,0, ZIP_HANDLE);
// from a file (by name): OpenZip("c:\\test.zip",0, ZIP_FILENAME);
// from a memory block: OpenZip(bufstart, buflen, ZIP_MEMORY);
// If the file is opened through a pipe, then items may only be
// accessed in increasing order, and an item may only be unzipped once,
// although GetZipItem can be called immediately before and after unzipping
// it. If it's opened i n any other way, then full random access is possible.
// Note: pipe input is not yet implemented.
///////////////////////////////////////////////////////////////////////////////
//
// GetZipItem()
//
// Purpose: Get information about an item in an open zip archive
//
// Parameters: hz - handle of open zip archive
// index - index number (0 based) of item in zip
// ze - pointer to a ZIPENTRY (if ANSI) or ZIPENTRYW struct
// (if Unicode)
//
// Returns: ZRESULT - ZR_OK if success, otherwise some other value
//
#ifdef _UNICODE
#define GetZipItem GetZipItemW
#else
#define GetZipItem GetZipItemA
#endif
ZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze);
ZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *ze);
// GetZipItem - call this to get information about an item in the zip.
// If index is -1 and the file wasn't opened through a pipe,
// then it returns information about the whole zipfile
// (and in particular ze.index returns the number of index items).
// Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY)
// See below for notes on what happens when you unzip such an item.
// Note: if you are opening the zip through a pipe, then random access
// is not possible and GetZipItem(-1) fails and you can't discover the number
// of items except by calling GetZipItem on each one of them in turn,
// starting at 0, until eventually the call fails. Also, in the event that
// you are opening through a pipe and the zip was itself created into a pipe,
// then then comp_size and sometimes unc_size as well may not be known until
// after the item has been unzipped.
///////////////////////////////////////////////////////////////////////////////
//
// FindZipItem()
//
// Purpose: Find item by name and return information about it
//
// Parameters: hz - handle of open zip archive
// name - name of file to look for inside zip archive
// ic - TRUE = case insensitive
// index - pointer to index number returned, or -1
// ze - pointer to a ZIPENTRY (if ANSI) or ZIPENTRYW struct
// (if Unicode)
//
// Returns: ZRESULT - ZR_OK if success, otherwise some other value
//
#ifdef _UNICODE
#define FindZipItem FindZipItemW
#else
#define FindZipItem FindZipItemA
#endif
ZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze);
ZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRYW *ze);
// FindZipItem - finds an item by name. ic means 'insensitive to case'.
// It returns the index of the item, and returns information about it.
// If nothing was found, then index is set to -1 and the function returns
// an error code.
///////////////////////////////////////////////////////////////////////////////
//
// UnzipItem()
//
// Purpose: Find item by index and unzip it
//
// Parameters: hz - handle of open zip archive
// index - index number of file to unzip
// dst - target file name of unzipped file
// len - for memory (ZIP_MEMORY. length of buffer;
// otherwise 0
// flags - indicates usage, see below; for files, this will be
// ZIP_FILENAME
//
// Returns: ZRESULT - ZR_OK if success, otherwise some other value
//
ZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len, DWORD flags);
// UnzipItem - given an index to an item, unzips it. You can unzip to:
// to a pipe: UnzipItem(hz,i, hpipe_write,0,ZIP_HANDLE);
// to a file (by handle): UnzipItem(hz,i, hfile,0,ZIP_HANDLE);
// to a file (by name): UnzipItem(hz,i, ze.name,0,ZIP_FILENAME);
// to a memory block: UnzipItem(hz,i, buf,buflen,ZIP_MEMORY);
// In the final case, if the buffer isn't large enough to hold it all,
// then the return code indicates that more is yet to come. If it was
// large enough, and you want to know precisely how big, GetZipItem.
// Note: zip files are normally stored with relative pathnames. If you
// unzip with ZIP_FILENAME a relative pathname then the item gets created
// relative to the current directory - it first ensures that all necessary
// subdirectories have been created. Also, the item may itself be a directory.
// If you unzip a directory with ZIP_FILENAME, then the directory gets created.
// If you unzip it to a handle or a memory block, then nothing gets created
// and it emits 0 bytes.
///////////////////////////////////////////////////////////////////////////////
//
// CloseZip()
//
// Purpose: Close an open zip archive
//
// Parameters: hz - handle to an open zip archive
//
// Returns: ZRESULT - ZR_OK if success, otherwise some other value
//
ZRESULT CloseZip(HZIP hz);
// CloseZip - the zip handle must be closed with this function.
unsigned int FormatZipMessage(ZRESULT code, char *buf,unsigned int len);
// FormatZipMessage - given an error code, formats it as a string.
// It returns the length of the error message. If buf/len points
// to a real buffer, then it also writes as much as possible into there.
// These are the result codes:
#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned,
#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage.
// The following come from general system stuff (e.g. files not openable)
#define ZR_GENMASK 0x0000FF00
#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle
#define ZR_NOFILE 0x00000200 // couldn't create/open the file
#define ZR_NOALLOC 0x00000300 // failed to allocate some resource
#define ZR_WRITE 0x00000400 // a general error writing to the file
#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip
#define ZR_MORE 0x00000600 // there's still more data to be unzipped
#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile
#define ZR_READ 0x00000800 // a general error reading the file
// The following come from mistakes on the part of the caller
#define ZR_CALLERMASK 0x00FF0000
#define ZR_ARGS 0x00010000 // general mistake with the arguments
#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't
#define ZR_MEMSIZE 0x00030000 // the memory size is too small
#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function
#define ZR_ENDED 0x00050000 // the zip creation has already been closed
#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken
#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped
#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip
// The following come from bugs within the zip library itself
#define ZR_BUGMASK 0xFF000000
#define ZR_NOTINITED 0x01000000 // initialisation didn't work
#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file
#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed
#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code
// e.g.
//
// SetCurrentDirectory("c:\\docs\\stuff");
// HZIP hz = OpenZip("c:\\stuff.zip",0,ZIP_FILENAME);
// ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index;
// for (int i=0; i<numitems; i++)
// { GetZipItem(hz,i,&ze);
// UnzipItem(hz,i,ze.name,0,ZIP_FILENAME);
// }
// CloseZip(hz);
//
//
// HRSRC hrsrc = FindResource(hInstance,MAKEINTRESOURCE(1),RT_RCDATA);
// HANDLE hglob = LoadResource(hInstance,hrsrc);
// void *zipbuf=LockResource(hglob);
// unsigned int ziplen=SizeofResource(hInstance,hrsrc);
// HZIP hz = OpenZip(zipbuf, ziplen, ZIP_MEMORY);
// - unzip to a membuffer -
// ZIPENTRY ze; int i; FindZipItem(hz,"file.dat",&i,&ze);
// char *ibuf = new char[ze.unc_size];
// UnzipItem(hz,i, ibuf, ze.unc_size,ZIP_MEMORY);
// delete[] buf;
// - unzip to a fixed membuff -
// ZIPENTRY ze; int i; FindZipItem(hz,"file.dat",&i,&ze);
// char ibuf[1024]; ZIPRESULT zr=ZR_MORE; unsigned long totsize=0;
// while (zr==ZR_MORE)
// { zr = UnzipItem(hz,i, ibuf,1024,ZIP_MEMORY);
// unsigned long bufsize=1024; if (zr==ZR_OK) bufsize=ze.unc_size-totsize;
// totsize+=bufsize;
// }
// - unzip to a pipe -
// HANDLE hthread=CreateWavReaderThread(&hread,&hwrite);
// FindZipItem(hz,"sound.wav",&i,&ze);
// UnzipItem(hz,i, hwrite,0,ZIP_HANDLE);
// CloseHandle(hwrite);
// WaitForSingleObject(hthread,INFINITE);
// CloseHandle(hread); CloseHandle(hthread);
// - finished -
// CloseZip(hz);
// // note: no need to free resources obtained through Find/Load/LockResource
//
//
// SetCurrentDirectory("c:\\docs\\pipedzipstuff");
// HANDLE hread,hwrite; CreatePipe(&hread,&hwrite);
// CreateZipWriterThread(hwrite);
// HZIP hz = OpenZip(hread,0,ZIP_HANDLE);
// for (int i=0; ; i++)
// { ZIPENTRY ze; ZRESULT res = GetZipItem(hz,i,&ze);
// if (res!=ZE_OK) break; // no more
// UnzipItem(hz,i, ze.name,0,ZIP_FILENAME);
// }
// CloseZip(hz);
//
// Now we indulge in a little skullduggery so that the code works whether
// the user has included just zip or both zip and unzip.
// Idea: if header files for both zip and unzip are present, then presumably
// the cpp files for zip and unzip are both present, so we will call
// one or the other of them based on a dynamic choice. If the header file
// for only one is present, then we will bind to that particular one.
HZIP OpenZipU(void *z,unsigned int len,DWORD flags);
ZRESULT CloseZipU(HZIP hz);
unsigned int FormatZipMessageU(ZRESULT code, char *buf,unsigned int len);
bool IsZipHandleU(HZIP hz);
#define OpenZip OpenZipU
#ifdef XZIP_H
#undef CloseZip
#define CloseZip(hz) (IsZipHandleU(hz)?CloseZipU(hz):CloseZipZ(hz))
#else
#define CloseZip CloseZipU
#define FormatZipMessage FormatZipMessageU
#endif
#endif //XUNZIP_H

749
bypy/windows/__main__.py Normal file
View File

@ -0,0 +1,749 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import absolute_import, division, print_function, unicode_literals
import errno
import glob
import os
import re
import runpy
import shutil
import stat
import subprocess
import sys
import zipfile
from bypy.constants import (
CL, LINK, MT, PREFIX, RC, SIGNTOOL, SRC as CALIBRE_DIR, SW, build_dir, is64bit,
python_major_minor_version, worker_env
)
from bypy.utils import py_compile, run, walk
iv = globals()['init_env']
calibre_constants = iv['calibre_constants']
QT_PREFIX = os.path.join(PREFIX, 'qt')
QT_DLLS, QT_PLUGINS, PYQT_MODULES = iv['QT_DLLS'], iv['QT_PLUGINS'], iv['PYQT_MODULES']
APPNAME, VERSION = calibre_constants['appname'], calibre_constants['version']
WINVER = VERSION + '.0'
machine = 'X64' if is64bit else 'X86'
j, d, a, b = os.path.join, os.path.dirname, os.path.abspath, os.path.basename
create_installer = runpy.run_path(
j(d(a(__file__)), 'wix.py'), {'calibre_constants': calibre_constants}
)['create_installer']
DESCRIPTIONS = {
'calibre': 'The main calibre program',
'ebook-viewer': 'The calibre e-book viewer',
'ebook-edit': 'The calibre e-book editor',
'lrfviewer': 'Viewer for LRF files',
'ebook-convert': 'Command line interface to the conversion/news download system',
'ebook-meta': 'Command line interface for manipulating e-book metadata',
'calibredb': 'Command line interface to the calibre database',
'calibre-launcher': 'Utility functions common to all executables',
'calibre-debug': 'Command line interface for calibre debugging/development',
'calibre-customize': 'Command line interface to calibre plugin system',
'calibre-server': 'Standalone calibre content server',
'calibre-parallel': 'calibre worker process',
'calibre-smtp': 'Command line interface for sending books via email',
'calibre-eject': 'Helper program for ejecting connected reader devices',
'calibre-file-dialog': 'Helper program to show file open/save dialogs',
}
# https://msdn.microsoft.com/en-us/library/windows/desktop/dn481241(v=vs.85).aspx
SUPPORTED_OS = {
'w7': '{35138b9a-5d96-4fbd-8e2d-a2440225f93a}',
'w8': '{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}',
'w81': '{1f676c76-80e1-4239-95bb-83d0f6d0da78}',
'w10': '{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}',
}
EXE_MANIFEST = '''\
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{w7}"/>
<supportedOS Id="{w8}"/>
<supportedOS Id="{w81}"/>
<supportedOS Id="{w10}"/>
</application>
</compatibility>
</assembly>
'''.format(**SUPPORTED_OS)
def printf(*args, **kw):
print(*args, **kw)
sys.stdout.flush()
def run_compiler(env, *cmd):
run(*cmd, cwd=env.obj_dir)
class Env(object):
def __init__(self, build_dir):
self.python_base = os.path.join(PREFIX, 'private', 'python')
self.portable_uncompressed_size = 0
self.src_root = CALIBRE_DIR
self.base = j(build_dir, 'winfrozen')
self.app_base = j(self.base, 'app')
self.rc_template = j(d(a(__file__)), 'template.rc')
self.py_ver = '.'.join(map(str, python_major_minor_version()))
self.lib_dir = j(self.app_base, 'Lib')
self.pylib = j(self.app_base, 'pylib.zip')
self.dll_dir = j(self.app_base, 'bin')
self.portable_base = j(d(self.base), 'Calibre Portable')
self.obj_dir = j(build_dir, 'launcher')
self.installer_dir = j(build_dir, 'wix')
self.dist = j(SW, 'dist')
def initbase(env):
os.makedirs(env.app_base)
os.mkdir(env.dll_dir)
try:
shutil.rmtree(env.dist)
except EnvironmentError as err:
if err.errno != errno.ENOENT:
raise
os.mkdir(env.dist)
def add_plugins(env, ext_dir):
printf('Adding plugins...')
tgt = env.dll_dir
for f in glob.glob(j(ext_dir, '*.pyd')):
shutil.copy2(f, tgt)
def freeze(env, ext_dir):
shutil.copy2(j(env.src_root, 'LICENSE'), env.base)
printf('Adding resources...')
tgt = j(env.app_base, 'resources')
if os.path.exists(tgt):
shutil.rmtree(tgt)
shutil.copytree(j(env.src_root, 'resources'), tgt)
printf('\tAdding misc binary deps')
def copybin(x):
shutil.copy2(x, env.dll_dir)
try:
shutil.copy2(x + '.manifest', env.dll_dir)
except EnvironmentError as err:
if err.errno != errno.ENOENT:
raise
bindir = os.path.join(PREFIX, 'bin')
for x in ('pdftohtml', 'pdfinfo', 'pdftoppm', 'jpegtran-calibre', 'cjpeg-calibre', 'optipng-calibre', 'JXRDecApp-calibre'):
copybin(os.path.join(bindir, x + '.exe'))
for f in glob.glob(os.path.join(bindir, '*.dll')):
if re.search(r'(easylzma|icutest)', f.lower()) is None:
copybin(f)
copybin(os.path.join(env.python_base, 'python%s.dll' % env.py_ver.replace('.', '')))
for x in glob.glob(os.path.join(env.python_base, 'DLLs', '*')): # python pyd modules
copybin(x)
for f in walk(os.path.join(env.python_base, 'Lib')):
if f.lower().endswith('.dll') and 'scintilla' not in f.lower():
copybin(f)
add_plugins(env, ext_dir)
printf('Adding Qt...')
for x in QT_DLLS:
copybin(os.path.join(QT_PREFIX, 'bin', x + '.dll'))
copybin(os.path.join(QT_PREFIX, 'bin', 'QtWebEngineProcess.exe'))
for x in 'libGLESv2 libEGL'.split():
copybin(os.path.join(QT_PREFIX, 'bin', x + '.dll'))
plugdir = j(QT_PREFIX, 'plugins')
tdir = j(env.app_base, 'plugins')
for d in QT_PLUGINS:
imfd = os.path.join(plugdir, d)
tg = os.path.join(tdir, d)
if os.path.exists(tg):
shutil.rmtree(tg)
shutil.copytree(imfd, tg)
for f in walk(tdir):
if not f.lower().endswith('.dll'):
os.remove(f)
for data_file in os.listdir(j(QT_PREFIX, 'resources')):
shutil.copy2(j(QT_PREFIX, 'resources', data_file), j(env.app_base, 'resources'))
shutil.copytree(j(QT_PREFIX, 'translations'), j(env.app_base, 'translations'))
printf('Adding python...')
def ignore_lib(root, items):
ans = []
for x in items:
ext = os.path.splitext(x)[1].lower()
if ext in ('.dll', '.chm', '.htm', '.txt'):
ans.append(x)
return ans
shutil.copytree(r'%s\Lib' % env.python_base, env.lib_dir, ignore=ignore_lib)
install_site_py(env)
# Fix win32com
sp_dir = j(env.lib_dir, 'site-packages')
comext = j(sp_dir, 'win32comext')
shutil.copytree(j(comext, 'shell'), j(sp_dir, 'win32com', 'shell'))
shutil.rmtree(comext)
for pat in ('PyQt5\\uic\\port_v3', ):
x = glob.glob(j(env.lib_dir, 'site-packages', pat))[0]
shutil.rmtree(x)
pyqt = j(env.lib_dir, 'site-packages', 'PyQt5')
for x in {x for x in os.listdir(pyqt) if x.endswith('.pyd')}:
if x.partition('.')[0] not in PYQT_MODULES and x != 'sip.pyd':
os.remove(j(pyqt, x))
with open(j(pyqt, '__init__.py') , 'r+b') as f:
raw = f.read()
nraw = raw.replace(b'def find_qt():', b'def find_qt():\n return # disabled for calibre')
if nraw == raw:
raise Exception('Failed to patch PyQt to disable dll directory manipulation')
f.seek(0), f.truncate(), f.write(nraw)
printf('Adding calibre sources...')
for x in glob.glob(j(CALIBRE_DIR, 'src', '*')):
if os.path.isdir(x):
if os.path.exists(os.path.join(x, '__init__.py')):
shutil.copytree(x, j(sp_dir, b(x)), ignore=shutil.ignore_patterns('*.pyc', '*.pyo'))
else:
shutil.copy(x, j(sp_dir, b(x)))
for x in (r'calibre\manual', r'calibre\plugins', 'pythonwin'):
deld = j(sp_dir, x)
if os.path.exists(deld):
shutil.rmtree(deld)
for x in os.walk(j(sp_dir, 'calibre')):
for f in x[-1]:
if not f.endswith('.py'):
os.remove(j(x[0], f))
extract_pyd_modules(env, sp_dir)
printf('Byte-compiling all python modules...')
for x in ('test', 'lib2to3'):
x = j(env.lib_dir, x)
if os.path.exists(x):
shutil.rmtree(x)
py_compile(env.lib_dir.replace(os.sep, '/'))
def embed_manifests(env):
printf('Embedding remaining manifests...')
for manifest in walk(env.base):
dll, ext = os.path.splitext(manifest)
if ext != '.manifest':
continue
res = 2
if os.path.splitext(dll)[1] == '.exe':
res = 1
if os.path.exists(dll) and open(manifest, 'rb').read().strip():
run(MT, '-manifest', manifest, '-outputresource:%s;%d' % (dll, res))
os.remove(manifest)
def extract_pyd_modules(env, site_packages_dir):
printf('\nExtracting .pyd modules from site-packages...')
def extract_pyd(path, root):
fullname = os.path.relpath(path, root).replace(os.sep, '/').replace('/', '.')
dest = os.path.join(env.dll_dir, fullname)
if os.path.exists(dest):
raise ValueError('Cannot extract %s into DLLs as it already exists' % fullname)
os.rename(path, dest)
bpy = dest[:-1]
if os.path.exists(bpy):
with open(bpy, 'rb') as f:
raw = f.read().strip().decode('utf-8')
if (not raw.startswith('def __bootstrap__') or not raw.endswith('__bootstrap__()')):
raise ValueError('The file %r has non bootstrap code' % bpy)
for ext in ('', 'c', 'o'):
try:
os.remove(bpy + ext)
except EnvironmentError as err:
if err.errno != errno.ENOENT:
raise
def find_pyds(base):
for dirpath, dirnames, filenames in os.walk(base):
for fname in filenames:
if fname.lower().endswith('.pyd'):
yield os.path.join(dirpath, fname)
def process_root(root, base=None):
for path in find_pyds(root):
extract_pyd(path, base or root)
def absp(x):
return os.path.normcase(os.path.abspath(os.path.join(site_packages_dir, x)))
roots = set()
for pth in glob.glob(os.path.join(site_packages_dir, '*.pth')):
for line in open(pth).readlines():
line = line.strip()
if line and not line.startswith('#') and os.path.exists(os.path.join(site_packages_dir, line)):
roots.add(absp(line))
for x in os.listdir(site_packages_dir):
x = absp(x)
if x in roots:
process_root(x)
elif os.path.isdir(x):
process_root(x, site_packages_dir)
elif x.lower().endswith('.pyd'):
extract_pyd(x, site_packages_dir)
def embed_resources(env, module, desc=None, extra_data=None, product_description=None):
icon_base = j(env.src_root, 'icons')
icon_map = {'calibre': 'library', 'ebook-viewer': 'viewer', 'ebook-edit': 'ebook-edit',
'lrfviewer': 'viewer', 'calibre-portable': 'library'}
file_type = 'DLL' if module.endswith('.dll') else 'APP'
with open(env.rc_template, 'rb') as f:
template = f.read().decode('utf-8')
bname = b(module)
internal_name = os.path.splitext(bname)[0]
icon = icon_map.get(internal_name, 'command-prompt')
if internal_name.startswith('calibre-portable-'):
icon = 'install'
icon = j(icon_base, icon + '.ico')
if desc is None:
defdesc = 'A dynamic link library' if file_type == 'DLL' else \
'An executable program'
desc = DESCRIPTIONS.get(internal_name, defdesc)
license = 'GNU GPL v3.0'
def e(val):
return val.replace('"', r'\"')
if product_description is None:
product_description = APPNAME + ' - E-book management'
rc = template.format(
icon=icon.replace('\\', '/'),
file_type=e(file_type),
file_version=e(WINVER.replace('.', ',')),
file_version_str=e(WINVER),
file_description=e(desc),
internal_name=e(internal_name),
original_filename=e(bname),
product_version=e(WINVER.replace('.', ',')),
product_version_str=e(VERSION),
product_name=e(APPNAME),
product_description=e(product_description),
legal_copyright=e(license),
legal_trademarks=e(APPNAME + ' is a registered U.S. trademark number 3,666,525')
)
if extra_data:
rc += '\nextra extra "%s"' % extra_data
tdir = env.obj_dir
rcf = j(tdir, bname + '.rc')
with open(rcf, 'w') as f:
f.write(rc)
res = j(tdir, bname + '.res')
run(RC, '/n', '/fo' + res, rcf)
return res
def install_site_py(env):
if not os.path.exists(env.lib_dir):
os.makedirs(env.lib_dir)
shutil.copy2(j(d(__file__), 'site.py'), env.lib_dir)
def build_portable_installer(env):
zf = a(j(env.dist, 'calibre-portable-%s.zip.lz' % VERSION)).replace(os.sep, '/')
usz = env.portable_uncompressed_size or os.path.getsize(zf)
def cc(src, obj):
cflags = '/c /EHsc /MT /W4 /Ox /nologo /D_UNICODE /DUNICODE /DPSAPI_VERSION=1'.split()
cflags.append(r'/I%s\include' % PREFIX)
cflags.append('/DUNCOMPRESSED_SIZE=%d' % usz)
printf('Compiling', obj)
cmd = [CL] + cflags + ['/Fo' + obj, src]
run_compiler(env, *cmd)
base = d(a(__file__))
src = j(base, 'portable-installer.cpp')
obj = j(env.obj_dir, b(src) + '.obj')
xsrc = j(base, 'XUnzip.cpp')
xobj = j(env.obj_dir, b(xsrc) + '.obj')
cc(src, obj)
cc(xsrc, xobj)
exe = j(env.dist, 'calibre-portable-installer-%s.exe' % VERSION)
printf('Linking', exe)
manifest = exe + '.manifest'
with open(manifest, 'wb') as f:
f.write(EXE_MANIFEST.encode('utf-8'))
cmd = [LINK] + [
'/INCREMENTAL:NO', '/MACHINE:' + machine,
'/LIBPATH:' + env.obj_dir, '/SUBSYSTEM:WINDOWS',
'/LIBPATH:' + (PREFIX + r'\lib'),
'/RELEASE', '/MANIFEST:EMBED', '/MANIFESTINPUT:' + manifest,
'/ENTRY:wWinMainCRTStartup',
'/OUT:' + exe, embed_resources(
env, exe, desc='Calibre Portable Installer', extra_data=zf, product_description='Calibre Portable Installer'),
xobj, obj, 'User32.lib', 'Shell32.lib', 'easylzma_s.lib',
'Ole32.lib', 'Shlwapi.lib', 'Kernel32.lib', 'Psapi.lib']
run(*cmd)
os.remove(zf)
def build_portable(env):
base = env.portable_base
if os.path.exists(base):
shutil.rmtree(base)
os.makedirs(base)
root = d(a(__file__))
src = j(root, 'portable.c')
obj = j(env.obj_dir, b(src) + '.obj')
cflags = '/c /EHsc /MT /W3 /Ox /nologo /D_UNICODE /DUNICODE'.split()
printf('Compiling', obj)
cmd = [CL] + cflags + ['/Fo' + obj, '/Tc' + src]
run_compiler(env, *cmd)
exe = j(base, 'calibre-portable.exe')
printf('Linking', exe)
cmd = [LINK] + [
'/INCREMENTAL:NO', '/MACHINE:' + machine,
'/LIBPATH:' + env.obj_dir, '/SUBSYSTEM:WINDOWS',
'/RELEASE',
'/ENTRY:wWinMainCRTStartup',
'/OUT:' + exe, embed_resources(env, exe, desc='Calibre Portable', product_description='Calibre Portable'),
obj, 'User32.lib']
run(*cmd)
printf('Creating portable installer')
shutil.copytree(env.base, j(base, 'Calibre'))
os.mkdir(j(base, 'Calibre Library'))
os.mkdir(j(base, 'Calibre Settings'))
name = '%s-portable-%s.zip' % (APPNAME, VERSION)
name = j(env.dist, name)
with zipfile.ZipFile(name, 'w', zipfile.ZIP_STORED) as zf:
add_dir_to_zip(zf, base, 'Calibre Portable')
env.portable_uncompressed_size = os.path.getsize(name)
subprocess.check_call([PREFIX + r'\bin\elzma.exe', '-9', '--lzip', name])
def sign_files(env, files):
args = [SIGNTOOL, 'sign', '/a', '/fd', 'sha256', '/td', 'sha256', '/d',
'calibre - E-book management', '/du',
'https://calibre-ebook.com', '/tr']
def runcmd(cmd):
for timeserver in ('http://sha256timestamp.ws.symantec.com/sha256/timestamp', 'http://timestamp.comodoca.com/rfc3161',):
try:
subprocess.check_call(cmd + [timeserver] + list(files))
break
except subprocess.CalledProcessError:
print ('Signing failed, retrying with different timestamp server')
else:
raise SystemExit('Signing failed')
runcmd(args)
def sign_installers(env):
printf('Signing installers...')
installers = set()
for f in glob.glob(j(env.dist, '*')):
if f.rpartition('.')[-1].lower() in {'exe', 'msi'}:
installers.add(f)
else:
os.remove(f)
if not installers:
raise ValueError('No installers found')
sign_files(env, installers)
def add_dir_to_zip(zf, path, prefix=''):
'''
Add a directory recursively to the zip file with an optional prefix.
'''
if prefix:
zi = zipfile.ZipInfo(prefix + '/')
zi.external_attr = 16
zf.writestr(zi, '')
cwd = os.path.abspath(os.getcwd())
try:
os.chdir(path)
fp = (prefix + ('/' if prefix else '')).replace('//', '/')
for f in os.listdir('.'):
arcname = fp + f
if os.path.isdir(f):
add_dir_to_zip(zf, f, prefix=arcname)
else:
zf.write(f, arcname)
finally:
os.chdir(cwd)
def build_utils(env):
def build(src, name, subsys='CONSOLE', libs='setupapi.lib'.split()):
printf('Building ' + name)
obj = j(env.obj_dir, os.path.basename(src) + '.obj')
cflags = '/c /EHsc /MD /W3 /Ox /nologo /D_UNICODE'.split()
ftype = '/T' + ('c' if src.endswith('.c') else 'p')
cmd = [CL] + cflags + ['/Fo' + obj, ftype + src]
run_compiler(env, *cmd)
exe = j(env.dll_dir, name)
mf = exe + '.manifest'
with open(mf, 'wb') as f:
f.write(EXE_MANIFEST.encode('utf-8'))
cmd = [LINK] + [
'/MACHINE:' + machine,
'/SUBSYSTEM:' + subsys, '/RELEASE', '/MANIFEST:EMBED', '/MANIFESTINPUT:' + mf,
'/OUT:' + exe] + [embed_resources(env, exe), obj] + libs
run(*cmd)
base = d(a(__file__))
build(j(base, 'file_dialogs.cpp'), 'calibre-file-dialog.exe', 'WINDOWS', 'Ole32.lib Shell32.lib'.split())
build(j(base, 'eject.c'), 'calibre-eject.exe')
def build_launchers(env, debug=False):
if not os.path.exists(env.obj_dir):
os.makedirs(env.obj_dir)
dflags = (['/Zi'] if debug else [])
dlflags = (['/DEBUG'] if debug else ['/INCREMENTAL:NO'])
base = d(a(__file__))
sources = [j(base, x) for x in ['util.c', ]]
objects = [j(env.obj_dir, b(x) + '.obj') for x in sources]
cflags = '/c /EHsc /W3 /Ox /nologo /D_UNICODE'.split()
cflags += ['/DPYDLL="python%s.dll"' % env.py_ver.replace('.', ''), '/I%s/include' % env.python_base]
for src, obj in zip(sources, objects):
cmd = [CL] + cflags + dflags + ['/MD', '/Fo' + obj, '/Tc' + src]
run_compiler(env, *cmd)
dll = j(env.obj_dir, 'calibre-launcher.dll')
ver = '.'.join(VERSION.split('.')[:2])
cmd = [LINK, '/DLL', '/VERSION:' + ver, '/LTCG', '/OUT:' + dll,
'/nologo', '/MACHINE:' + machine] + dlflags + objects + \
[embed_resources(env, dll),
'/LIBPATH:%s/libs' % env.python_base,
'delayimp.lib', 'user32.lib', 'shell32.lib',
'python%s.lib' % env.py_ver.replace('.', ''),
'/delayload:python%s.dll' % env.py_ver.replace('.', '')]
printf('Linking calibre-launcher.dll')
run(*cmd)
src = j(base, 'main.c')
shutil.copy2(dll, env.dll_dir)
basenames, modules, functions = calibre_constants['basenames'], calibre_constants['modules'], calibre_constants['functions']
for typ in ('console', 'gui', ):
printf('Processing %s launchers' % typ)
subsys = 'WINDOWS' if typ == 'gui' else 'CONSOLE'
for mod, bname, func in zip(modules[typ], basenames[typ], functions[typ]):
cflags = '/c /EHsc /MT /W3 /O1 /nologo /D_UNICODE /DUNICODE /GS-'.split()
if typ == 'gui':
cflags += ['/DGUI_APP=']
cflags += ['/DMODULE="%s"' % mod, '/DBASENAME="%s"' % bname,
'/DFUNCTION="%s"' % func]
dest = j(env.obj_dir, bname + '.obj')
printf('Compiling', bname)
cmd = [CL] + cflags + dflags + ['/Tc' + src, '/Fo' + dest]
run_compiler(env, *cmd)
exe = j(env.base, bname + '.exe')
lib = dll.replace('.dll', '.lib')
u32 = ['user32.lib']
printf('Linking', bname)
mf = dest + '.manifest'
with open(mf, 'wb') as f:
f.write(EXE_MANIFEST.encode('utf-8'))
cmd = [LINK] + [
'/MACHINE:' + machine, '/NODEFAULTLIB', '/ENTRY:start_here',
'/LIBPATH:' + env.obj_dir, '/SUBSYSTEM:' + subsys,
'/LIBPATH:%s/libs' % env.python_base, '/RELEASE',
'/MANIFEST:EMBED', '/MANIFESTINPUT:' + mf,
'user32.lib', 'kernel32.lib',
'/OUT:' + exe] + u32 + dlflags + [embed_resources(env, exe), dest, lib]
run(*cmd)
def add_to_zipfile(zf, name, base, zf_names):
abspath = j(base, name)
name = name.replace(os.sep, '/')
if name in zf_names:
raise ValueError('Already added %r to zipfile [%r]' % (name, abspath))
zinfo = zipfile.ZipInfo(filename=name, date_time=(1980, 1, 1, 0, 0, 0))
if os.path.isdir(abspath):
if not os.listdir(abspath):
return
zinfo.external_attr = 0o700 << 16
zf.writestr(zinfo, '')
for x in os.listdir(abspath):
add_to_zipfile(zf, name + os.sep + x, base, zf_names)
else:
ext = os.path.splitext(name)[1].lower()
if ext in ('.dll',):
raise ValueError('Cannot add %r to zipfile' % abspath)
zinfo.external_attr = 0o600 << 16
if ext in ('.py', '.pyc', '.pyo'):
with open(abspath, 'rb') as f:
zf.writestr(zinfo, f.read())
zf_names.add(name)
def archive_lib_dir(env):
printf('Putting all python code into a zip file for performance')
zf_names = set()
with zipfile.ZipFile(env.pylib, 'w', zipfile.ZIP_STORED) as zf:
# Add everything in Lib except site-packages to the zip file
for x in os.listdir(env.lib_dir):
if x == 'site-packages':
continue
add_to_zipfile(zf, x, env.lib_dir, zf_names)
sp = j(env.lib_dir, 'site-packages')
# Special handling for pywin32
handled = {'pywin32.pth', 'win32'}
base = j(sp, 'win32', 'lib')
for x in os.listdir(base):
if os.path.splitext(x)[1] not in ('.exe',):
add_to_zipfile(zf, x, base, zf_names)
base = os.path.dirname(base)
for x in os.listdir(base):
if not os.path.isdir(j(base, x)):
if os.path.splitext(x)[1] not in ('.exe',):
add_to_zipfile(zf, x, base, zf_names)
# We dont want the site.py (if any) from site-packages
handled.add('site.pyo')
# The rest of site-packages
for x in os.listdir(sp):
if x in handled or x.endswith('.egg-info'):
continue
absp = j(sp, x)
if os.path.isdir(absp):
if not os.listdir(absp):
continue
add_to_zipfile(zf, x, sp, zf_names)
else:
add_to_zipfile(zf, x, sp, zf_names)
shutil.rmtree(env.lib_dir)
def copy_crt_and_d3d(env):
printf('Copying CRT and D3D...')
plat = ('x64' if is64bit else 'x86')
for key, val in worker_env.items():
if 'COMNTOOLS' in key.upper():
redist_dir = os.path.dirname(os.path.dirname(val.rstrip(os.sep)))
redist_dir = os.path.join(redist_dir, 'VC', 'Redist', 'MSVC')
vc_path = glob.glob(os.path.join(redist_dir, '*', plat, '*.CRT'))[0]
break
else:
raise SystemExit('Could not find Visual Studio redistributable CRT')
sdk_path = os.path.join(
worker_env['UNIVERSALCRTSDKDIR'], 'Redist', worker_env['WINDOWSSDKVERSION'],
'ucrt', 'DLLs', plat)
if not os.path.exists(sdk_path):
raise SystemExit('Windows 10 Universal CRT redistributable not found at: %r' % sdk_path)
d3d_path = os.path.join(
worker_env['WINDOWSSDKDIR'], 'Redist', 'D3D', plat)
if not os.path.exists(d3d_path):
raise SystemExit('Windows 10 D3D redistributable not found at: %r' % d3d_path)
mesa_path = os.path.join(os.environ['MESA'], ('64' if is64bit else '32'), 'opengl32sw.dll')
if not os.path.exists(mesa_path):
raise SystemExit('Mesa DLLs (opengl32sw.dll) not found at: %r' % mesa_path)
def copy_dll(dll):
shutil.copy2(dll, env.dll_dir)
os.chmod(os.path.join(env.dll_dir, b(dll)), stat.S_IRWXU)
for dll in glob.glob(os.path.join(d3d_path, '*.dll')):
if os.path.basename(dll).lower().startswith('d3dcompiler_'):
copy_dll(dll)
copy_dll(mesa_path)
for dll in glob.glob(os.path.join(sdk_path, '*.dll')):
copy_dll(dll)
for dll in glob.glob(os.path.join(vc_path, '*.dll')):
bname = os.path.basename(dll)
if not bname.startswith('vccorlib') and not bname.startswith('concrt'):
# Those two DLLs are not required vccorlib is for the CORE CLR
# I think concrt is the concurrency runtime for C++ which I believe
# nothing in calibre currently uses
copy_dll(dll)
def sign_executables(env):
files_to_sign = []
for path in walk(env.base):
if path.lower().endswith('.exe'):
files_to_sign.append(path)
printf('Signing {} exe files'.format(len(files_to_sign)))
sign_files(env, files_to_sign)
def main():
ext_dir = globals()['ext_dir']
args = globals()['args']
run_tests = iv['run_tests']
env = Env(build_dir())
initbase(env)
build_launchers(env)
build_utils(env)
freeze(env, ext_dir)
embed_manifests(env)
copy_crt_and_d3d(env)
archive_lib_dir(env)
if not args.skip_tests:
run_tests(os.path.join(env.base, 'calibre-debug.exe'), env.base)
if args.sign_installers:
sign_executables(env)
create_installer(env)
if not is64bit:
build_portable(env)
build_portable_installer(env)
if args.sign_installers:
sign_installers(env)
def develop_launcher():
import subprocess
def r(*a):
subprocess.check_call(list(a))
r(
'cl.EXE', '/c', '/EHsc', '/MT', '/W3', '/O1', '/nologo', '/D_UNICODE', '/DUNICODE', '/GS-',
'/DMODULE="calibre.debug"', '/DBASENAME="calibre-debug"', '/DFUNCTION="main"',
r'/TcC:\r\src\bypy\windows\main.c', r'/Fo..\launcher\calibre-debug.obj'
)
r(
'link.EXE', '/MACHINE:X86', '/NODEFAULTLIB', '/ENTRY:start_here',
r'/LIBPATH:..\launcher', '/SUBSYSTEM:CONSOLE',
r'/LIBPATH:C:\r\sw32\sw\private\python/libs', '/RELEASE',
'/MANIFEST:EMBED', r'/MANIFESTINPUT:..\launcher\calibre-debug.obj.manifest',
'user32.lib', 'kernel32.lib', r'/OUT:calibre-debug.exe',
'user32.lib', '/INCREMENTAL:NO', r'..\launcher\calibre-debug.exe.res',
r'..\launcher\calibre-debug.obj', r'..\launcher\calibre-launcher.lib'
)
if __name__ == '__main__':
main()

423
bypy/windows/eject.c Normal file
View File

@ -0,0 +1,423 @@
/*
* eject.c
* Copyright (C) 2013 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include "Windows.h"
#include <stdio.h>
#include <wchar.h>
#include <winioctl.h>
#include <setupapi.h>
#include <devguid.h>
#include <cfgmgr32.h>
#define BUFSIZE 4096
#define LOCK_TIMEOUT 10000 // 10 Seconds
#define LOCK_RETRIES 20
#define BOOL2STR(x) ((x) ? L"True" : L"False")
// Error handling {{{
static void show_error(LPCWSTR msg) {
MessageBeep(MB_ICONERROR);
MessageBoxW(NULL, msg, L"Error", MB_OK|MB_ICONERROR);
}
static void show_detailed_error(LPCWSTR preamble, LPCWSTR msg, int code) {
LPWSTR buf;
buf = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, sizeof(WCHAR)*
(wcslen(msg) + wcslen(preamble) + 80));
_snwprintf_s(buf,
LocalSize(buf) / sizeof(WCHAR), _TRUNCATE,
L"%s\r\n %s (Error Code: %d)\r\n",
preamble, msg, code);
show_error(buf);
LocalFree(buf);
}
static void print_detailed_error(LPCWSTR preamble, LPCWSTR msg, int code) {
fwprintf_s(stderr, L"%s\r\n %s (Error Code: %d)\r\n", preamble, msg, code);
fflush(stderr);
}
static void show_last_error_crt(LPCWSTR preamble) {
WCHAR buf[BUFSIZE];
int err = 0;
_get_errno(&err);
_wcserror_s(buf, BUFSIZE, err);
show_detailed_error(preamble, buf, err);
}
static void show_last_error(LPCWSTR preamble) {
WCHAR *msg = NULL;
DWORD dw = GetLastError();
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&msg,
0, NULL );
show_detailed_error(preamble, msg, (int)dw);
}
static void print_last_error(LPCWSTR preamble) {
WCHAR *msg = NULL;
DWORD dw = GetLastError();
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&msg,
0, NULL );
print_detailed_error(preamble, msg, (int)dw);
}
// }}}
static void print_help() {
fwprintf_s(stderr, L"Usage: calibre-eject.exe drive-letter1 [drive-letter2 drive-letter3 ...]");
}
static LPWSTR root_path = L"X:\\", device_path = L"X:", volume_access_path = L"\\\\.\\X:";
static wchar_t dos_device_name[MAX_PATH];
static UINT drive_type = 0;
static long device_number = -1;
static DEVINST dev_inst = 0, dev_inst_parent = 0;
// Unmount and eject volumes (drives) {{{
static HANDLE open_volume(wchar_t drive_letter) {
DWORD access_flags;
switch(drive_type) {
case DRIVE_REMOVABLE:
access_flags = GENERIC_READ | GENERIC_WRITE;
break;
case DRIVE_CDROM:
access_flags = GENERIC_READ;
break;
default:
fwprintf_s(stderr, L"Cannot eject %c: Drive type is incorrect.\r\n", drive_letter);
fflush(stderr);
return INVALID_HANDLE_VALUE;
}
return CreateFileW(volume_access_path, access_flags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
}
static BOOL lock_volume(HANDLE volume) {
DWORD bytes_returned;
DWORD sleep_amount = LOCK_TIMEOUT / LOCK_RETRIES;
int try_count;
// Do this in a loop until a timeout period has expired
for (try_count = 0; try_count < LOCK_RETRIES; try_count++) {
if (DeviceIoControl(volume,
FSCTL_LOCK_VOLUME,
NULL, 0,
NULL, 0,
&bytes_returned,
NULL))
return TRUE;
Sleep(sleep_amount);
}
return FALSE;
}
static BOOL dismount_volume(HANDLE volume) {
DWORD bytes_returned;
return DeviceIoControl( volume,
FSCTL_DISMOUNT_VOLUME,
NULL, 0,
NULL, 0,
&bytes_returned,
NULL);
}
static BOOL disable_prevent_removal_of_volume(HANDLE volume) {
DWORD bytes_returned;
PREVENT_MEDIA_REMOVAL PMRBuffer;
PMRBuffer.PreventMediaRemoval = FALSE;
return DeviceIoControl( volume,
IOCTL_STORAGE_MEDIA_REMOVAL,
&PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
NULL, 0,
&bytes_returned,
NULL);
}
static BOOL auto_eject_volume(HANDLE volume) {
DWORD bytes_returned;
return DeviceIoControl( volume,
IOCTL_STORAGE_EJECT_MEDIA,
NULL, 0,
NULL, 0,
&bytes_returned,
NULL);
}
static BOOL unmount_drive(wchar_t drive_letter, BOOL *remove_safely, BOOL *auto_eject) {
// Unmount the drive identified by drive_letter. Code adapted from:
// http://support.microsoft.com/kb/165721
HANDLE volume;
*remove_safely = FALSE; *auto_eject = FALSE;
volume = open_volume(drive_letter);
if (volume == INVALID_HANDLE_VALUE) return FALSE;
// Lock and dismount the volume.
if (lock_volume(volume) && dismount_volume(volume)) {
*remove_safely = TRUE;
// Set prevent removal to false and eject the volume.
if (disable_prevent_removal_of_volume(volume) && auto_eject_volume(volume))
*auto_eject = TRUE;
}
CloseHandle(volume);
return TRUE;
}
// }}}
// Eject USB device {{{
static void get_device_number(wchar_t drive_letter) {
HANDLE volume;
DWORD bytes_returned = 0;
STORAGE_DEVICE_NUMBER sdn;
volume = CreateFileW(volume_access_path, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (volume == INVALID_HANDLE_VALUE) {
print_last_error(L"Failed to open volume while getting device number");
return;
}
if (DeviceIoControl(volume,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, &sdn, sizeof(sdn),
&bytes_returned, NULL))
device_number = sdn.DeviceNumber;
CloseHandle(volume);
}
static DEVINST get_dev_inst_by_device_number(long device_number, UINT drive_type, LPWSTR dos_device_name) {
GUID *guid;
HDEVINFO dev_info;
DWORD index, bytes_returned;
BOOL bRet, is_floppy;
BYTE Buf[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd;
long res;
HANDLE drive;
STORAGE_DEVICE_NUMBER sdn;
SP_DEVICE_INTERFACE_DATA spdid;
SP_DEVINFO_DATA spdd;
DWORD size;
is_floppy = (wcsstr(dos_device_name, L"\\Floppy") != NULL); // is there a better way?
switch (drive_type) {
case DRIVE_REMOVABLE:
guid = ( (is_floppy) ? (GUID*)&GUID_DEVINTERFACE_FLOPPY : (GUID*)&GUID_DEVINTERFACE_DISK );
break;
case DRIVE_FIXED:
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
break;
case DRIVE_CDROM:
guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
break;
default:
fwprintf_s(stderr, L"Invalid drive type at line: %d\r\n", __LINE__);
fflush(stderr);
return 0;
}
// Get device interface info set handle
// for all devices attached to system
dev_info = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (dev_info == INVALID_HANDLE_VALUE) {
fwprintf_s(stderr, L"Failed to setup class devs at line: %d\r\n", __LINE__);
fflush(stderr);
return 0;
}
// Retrieve a context structure for a device interface
// of a device information set.
index = 0;
bRet = FALSE;
pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
spdid.cbSize = sizeof(spdid);
while ( TRUE ) {
bRet = SetupDiEnumDeviceInterfaces(dev_info, NULL,
guid, index, &spdid);
if ( !bRet ) break;
size = 0;
SetupDiGetDeviceInterfaceDetail(dev_info,
&spdid, NULL, 0, &size, NULL);
if ( size!=0 && size<=sizeof(Buf) ) {
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
ZeroMemory((PVOID)&spdd, sizeof(spdd));
spdd.cbSize = sizeof(spdd);
res = SetupDiGetDeviceInterfaceDetail(dev_info, &spdid, pspdidd, size, &size, &spdd);
if ( res ) {
drive = CreateFile(pspdidd->DevicePath,0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if ( drive != INVALID_HANDLE_VALUE ) {
bytes_returned = 0;
res = DeviceIoControl(drive,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, &sdn, sizeof(sdn),
&bytes_returned, NULL);
if ( res ) {
if ( device_number == (long)sdn.DeviceNumber ) {
CloseHandle(drive);
SetupDiDestroyDeviceInfoList(dev_info);
return spdd.DevInst;
}
}
CloseHandle(drive);
}
}
}
index++;
}
SetupDiDestroyDeviceInfoList(dev_info);
fwprintf_s(stderr, L"Invalid device number at line: %d\r\n", __LINE__);
fflush(stderr);
return 0;
}
static void get_parent_device(wchar_t drive_letter) {
get_device_number(drive_letter);
if (device_number == -1) return;
if (QueryDosDeviceW(device_path, dos_device_name, MAX_PATH) == 0) {
print_last_error(L"Failed to query DOS device name");
return;
}
dev_inst = get_dev_inst_by_device_number(device_number,
drive_type, dos_device_name);
if (dev_inst == 0) {
fwprintf_s(stderr, L"Failed to get device by device number");
fflush(stderr);
return;
}
if (CM_Get_Parent(&dev_inst_parent, dev_inst, 0) != CR_SUCCESS) {
fwprintf_s(stderr, L"Failed to get device parent from CM");
fflush(stderr);
return;
}
}
static int eject_device() {
int tries;
CONFIGRET res;
PNP_VETO_TYPE VetoType;
WCHAR VetoNameW[MAX_PATH];
BOOL success;
for ( tries = 0; tries < 3; tries++ ) {
VetoNameW[0] = 0;
res = CM_Request_Device_EjectW(dev_inst_parent,
&VetoType, VetoNameW, MAX_PATH, 0);
success = (res==CR_SUCCESS &&
VetoType==PNP_VetoTypeUnknown);
if ( success ) {
break;
}
Sleep(500); // required to give the next tries a chance!
}
if (!success) {
fwprintf_s(stderr, L"CM_Request_Device_Eject failed after three tries\r\n");
fflush(stderr);
}
return (success) ? 0 : 1;
}
// }}}
int wmain(int argc, wchar_t *argv[ ]) {
int i = 0;
wchar_t drive_letter;
BOOL remove_safely, auto_eject;
// Validate command line arguments
if (argc < 2) { print_help(); return 1; }
for (i = 1; i < argc; i++) {
if (wcsnlen_s(argv[i], 2) != 1) { print_help(); return 1; }
}
// Unmount all mounted volumes and eject volume media
for (i = 1; i < argc; i++) {
drive_letter = *argv[i];
root_path[0] = drive_letter;
device_path[0] = drive_letter;
volume_access_path[4] = drive_letter;
drive_type = GetDriveTypeW(root_path);
if (i == 1 && device_number == -1) {
get_parent_device(drive_letter);
}
if (device_number != -1) {
unmount_drive(drive_letter, &remove_safely, &auto_eject);
fwprintf_s(stdout, L"Unmounting: %c: Remove safely: %s Media Ejected: %s\r\n",
drive_letter, BOOL2STR(remove_safely), BOOL2STR(auto_eject));
fflush(stdout);
}
}
// Eject the parent USB device
if (device_number == -1) {
fwprintf_s(stderr, L"Cannot eject, failed to get device number\r\n");
fflush(stderr);
return 1;
}
if (dev_inst_parent == 0) {
fwprintf_s(stderr, L"Cannot eject, failed to get device parent\r\n");
fflush(stderr);
return 1;
}
return eject_device();
}

9
bypy/windows/en-us.xml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="AdvancedWelcomeEulaDlgDescriptionPerUser">Click Advanced to change installation settings.</String>
<String Id="ProgressTextFileCost">Computing space requirements, this may take up to five minutes...</String>
<String Id="ProgressTextCostInitialize">Computing space requirements, this may take up to five minutes...</String>
<String Id="ProgressTextCostFinalize">Computing space requirements, this may take up to five minutes...</String>
<String Id="WaitForCostingDlgText">Please wait while the installer finishes determining your disk space requirements, this may take up to five minutes...</String>
</WixLocalization>

View File

@ -0,0 +1,355 @@
/*
* file_dialogs.c
* Copyright (C) 2016 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#ifndef _UNICODE
#define _UNICODE
#endif
#include <Windows.h>
#include <Shobjidl.h>
#include <comdef.h>
#include <stdio.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#define PRINTERR(x) fprintf(stderr, "%s", x); fflush(stderr);
#define SECRET_SIZE 32
void set_dpi_aware() {
// Try SetProcessDpiAwareness first
HINSTANCE sh_core = LoadLibraryW(L"Shcore.dll");
if (sh_core) {
enum ProcessDpiAwareness
{
ProcessDpiUnaware = 0,
ProcessSystemDpiAware = 1,
ProcessPerMonitorDpiAware = 2
};
typedef HRESULT (WINAPI* SetProcessDpiAwarenessFuncType)(ProcessDpiAwareness);
SetProcessDpiAwarenessFuncType SetProcessDpiAwarenessFunc = reinterpret_cast<SetProcessDpiAwarenessFuncType>(GetProcAddress(sh_core, "SetProcessDpiAwareness"));
if (SetProcessDpiAwarenessFunc) {
// We only check for E_INVALIDARG because we would get
// E_ACCESSDENIED if the DPI was already set previously
// and S_OK means the call was successful
if (SetProcessDpiAwarenessFunc(ProcessPerMonitorDpiAware) == E_INVALIDARG) {
PRINTERR("Failed to set process DPI awareness using SetProcessDpiAwareness");
} else {
FreeLibrary(sh_core);
return;
}
}
FreeLibrary(sh_core);
}
// Fall back to SetProcessDPIAware if SetProcessDpiAwareness
// is not available on this system
HINSTANCE user32 = LoadLibraryW(L"user32.dll");
if (user32) {
typedef BOOL (WINAPI* SetProcessDPIAwareFuncType)(void);
SetProcessDPIAwareFuncType SetProcessDPIAwareFunc = reinterpret_cast<SetProcessDPIAwareFuncType>(GetProcAddress(user32, "SetProcessDPIAware"));
if (SetProcessDPIAwareFunc) {
if (!SetProcessDPIAwareFunc()) {
PRINTERR("Failed to set process DPI awareness using SetProcessDPIAware");
}
}
FreeLibrary(user32);
}
}
bool write_bytes(HANDLE pipe, DWORD sz, const char* buf) {
DWORD written = 0;
if (!WriteFile(pipe, buf, sz, &written, NULL)) {
fprintf(stderr, "Failed to write to pipe. GetLastError()=%d\n", GetLastError()); fflush(stderr); return false;
}
if (written != sz) {
fprintf(stderr, "Failed to write to pipe. Incomplete write, leftover bytes: %d", sz - written); fflush(stderr); return false;
}
return true;
}
bool read_bytes(size_t sz, char* buf, bool allow_incomplete=false) {
char *ptr = buf, *limit = buf + sz;
while(limit > ptr && !feof(stdin) && !ferror(stdin)) {
ptr += fread(ptr, 1, limit - ptr, stdin);
}
if (ferror(stdin)) { PRINTERR("Failed to read from stdin!"); return false; }
if (ptr - buf != sz) { if (!allow_incomplete) PRINTERR("Truncated input!"); return false; }
return true;
}
bool from_utf8(size_t sz, const char *src, LPWSTR* ans) {
int asz = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, (int)sz, NULL, 0);
if (!asz) { PRINTERR("Failed to get size of UTF-8 string"); return false; }
*ans = (LPWSTR)calloc(asz+1, sizeof(wchar_t));
if(*ans == NULL) { PRINTERR("Out of memory!"); return false; }
asz = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, (int)sz, *ans, asz);
if (!asz) { PRINTERR("Failed to convert UTF-8 string"); return false; }
return true;
}
char* to_utf8(LPCWSTR src, int *sz) {
// Convert to a null-terminated UTF-8 encoded bytearray, allocated on the heap
char *ans = NULL;
*sz = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, NULL, 0, NULL, NULL);
if (!*sz) { PRINTERR("Failed to get size of UTF-16 string"); return NULL; }
ans = (char*)calloc((*sz) + 1, sizeof(char));
if (ans == NULL) { PRINTERR("Out of memory!"); return NULL; }
*sz = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, ans, *sz, NULL, NULL);
if (!*sz) { PRINTERR("Failed to convert UTF-16 string"); return NULL; }
return ans;
}
static char* rsbuf = NULL;
bool read_string(unsigned short sz, LPWSTR* ans) {
memset(rsbuf, 0, 65537);
if (!read_bytes(sz, rsbuf)) return false;
if (!from_utf8(sz, rsbuf, ans)) return false;
return true;
}
COMDLG_FILTERSPEC *read_file_types(UINT *num_file_types) {
char buf[10] = {0};
COMDLG_FILTERSPEC *ans = NULL;
if(!read_bytes(sizeof(unsigned short), buf)) return NULL;
*num_file_types = *((unsigned short*)buf);
if (*num_file_types < 1 || *num_file_types > 500) { PRINTERR("Invalid number of file types"); return NULL; }
ans = (COMDLG_FILTERSPEC*)calloc((*num_file_types) + 1, sizeof(COMDLG_FILTERSPEC));
if (ans == NULL) { PRINTERR("Out of memory!"); return NULL; }
for(unsigned short i = 0; i < *num_file_types; i++) {
if(!read_bytes(sizeof(unsigned short), buf)) return NULL;
if(!read_string(*((unsigned short*)buf), (LPWSTR*)&(ans[i].pszName))) return NULL;
if(!read_bytes(sizeof(unsigned short), buf)) return NULL;
if(!read_string(*((unsigned short*)buf), (LPWSTR*)&(ans[i].pszSpec))) return NULL;
}
return ans;
}
static void print_com_error(HRESULT hr, const char *msg) {
_com_error err(hr);
LPCWSTR emsg = (LPCWSTR) err.ErrorMessage();
int sz = 0;
const char *buf = to_utf8(emsg, &sz);
if (buf == NULL) { fprintf(stderr, "%s", msg); }
else { fprintf(stderr, "%s: (HRESULT=0x%x) %s\n", msg, hr, buf); }
fflush(stderr);
}
#define REPORTERR(hr, x) { print_com_error(hr, x); ret = 1; goto error; }
#define CALLCOM(x, err) hr = x; if(FAILED(hr)) REPORTERR(hr, err)
int show_dialog(HANDLE pipe, char *secret, HWND parent, bool save_dialog, LPWSTR title, LPWSTR folder, LPWSTR filename, LPWSTR save_path, bool multiselect, bool confirm_overwrite, bool only_dirs, bool no_symlinks, COMDLG_FILTERSPEC *file_types, UINT num_file_types, LPWSTR default_extension) {
int ret = 0, name_sz = 0;
IFileDialog *pfd = NULL;
IShellItemArray *items = NULL;
IShellItem *item = NULL, *folder_item = NULL, *save_path_item = NULL;
char *path = NULL;
DWORD options = 0, item_count = 0;
LPWSTR name = NULL;
HRESULT hr = S_OK;
hr = CoInitialize(NULL);
if (FAILED(hr)) { PRINTERR("Failed to initialize COM"); return 1; }
CALLCOM(CoCreateInstance((save_dialog ? CLSID_FileSaveDialog : CLSID_FileOpenDialog),
NULL, CLSCTX_INPROC_SERVER, (save_dialog ? IID_IFileSaveDialog : IID_IFileOpenDialog),
reinterpret_cast<LPVOID*>(&pfd)),
"Failed to create COM object for file dialog")
CALLCOM(pfd->GetOptions(&options), "Failed to get options")
options |= FOS_PATHMUSTEXIST;
if (no_symlinks) options |= FOS_NODEREFERENCELINKS;
if (save_dialog) {
options |= FOS_NOREADONLYRETURN;
if (confirm_overwrite) options |= FOS_OVERWRITEPROMPT;
if (save_path != NULL) {
hr = SHCreateItemFromParsingName(save_path, NULL, IID_IShellItem, reinterpret_cast<void **>(&save_path_item));
// Failure to set initial save path is not critical
if (SUCCEEDED(hr)) ((IFileSaveDialog*)pfd)->SetSaveAsItem(save_path_item);
}
} else {
if (multiselect) options |= FOS_ALLOWMULTISELECT;
if (only_dirs) options |= FOS_PICKFOLDERS;
options |= FOS_FILEMUSTEXIST;
}
CALLCOM(pfd->SetOptions(options), "Failed to set options")
if (title != NULL) { CALLCOM(pfd->SetTitle(title), "Failed to set title") }
if (folder != NULL) {
hr = SHCreateItemFromParsingName(folder, NULL, IID_IShellItem, reinterpret_cast<void **>(&folder_item));
// Failure to set initial folder is not critical
if (SUCCEEDED(hr)) pfd->SetFolder(folder_item);
}
if (filename != NULL) pfd->SetFileName(filename); // Failure is not critical
if (!(options & FOS_PICKFOLDERS) && file_types != NULL && num_file_types > 0) {
CALLCOM(pfd->SetFileTypes(num_file_types, file_types), "Failed to set file types")
CALLCOM(pfd->SetFileTypeIndex(1), "Failed to set file type index")
}
if (default_extension != NULL) {
CALLCOM(pfd->SetDefaultExtension(default_extension), "Failed to set default extension")
}
hr = pfd->Show(parent);
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) goto error;
if (FAILED(hr)) REPORTERR(hr, "Failed to show dialog")
if (save_dialog) {
CALLCOM(pfd->GetResult(&item), "Failed to get save dialog result");
CALLCOM(item->GetDisplayName(SIGDN_FILESYSPATH, &name), "Failed to get display name of save dialog result");
path = to_utf8(name, &name_sz);
CoTaskMemFree(name); name = NULL;
if (path == NULL) return 1;
if (!write_bytes(pipe, SECRET_SIZE+1, secret)) return 1;
if (!write_bytes(pipe, name_sz, path)) return 1;
} else {
CALLCOM(((IFileOpenDialog*)pfd)->GetResults(&items), "Failed to get dialog results");
CALLCOM(items->GetCount(&item_count), "Failed to get count of results");
if (item_count > 0) {
if (!write_bytes(pipe, SECRET_SIZE+1, secret)) return 1;
for (DWORD i = 0; i < item_count; i++) {
CALLCOM(items->GetItemAt(i, &item), "Failed to get result item");
if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) {
path = to_utf8(name, &name_sz);
CoTaskMemFree(name); name = NULL;
if (path == NULL) return 1;
if (!write_bytes(pipe, name_sz, path)) return 1;
}
}
}
}
error:
if(pfd) pfd->Release();
CoUninitialize();
return ret;
}
#define READ(x, y) if (!read_bytes((x), (y))) return 1;
#define CHECK_KEY(x) (key_size == sizeof(x) - 1 && memcmp(buf, x, sizeof(x) - 1) == 0)
#define READSTR(x) READ(sizeof(unsigned short), buf); if(!read_string(*((unsigned short*)buf), &x)) return 1;
#define SETBINARY(x) if(_setmode(_fileno(x), _O_BINARY) == -1) { PRINTERR("Failed to set binary mode"); return 1; }
#define READBOOL(x) READ(1, buf); x = !!buf[0];
HANDLE open_named_pipe(LPWSTR pipename) {
HANDLE ans = INVALID_HANDLE_VALUE;
while(true) {
ans = CreateFileW(pipename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (ans != INVALID_HANDLE_VALUE) break;
if (GetLastError() != ERROR_PIPE_BUSY) {
fprintf(stderr, "Failed to open pipe. GetLastError()=%d\n", GetLastError()); fflush(stderr); return ans;
}
if (!WaitNamedPipeW(pipename, 20000)) {
fprintf(stderr, "Failed to open pipe. 20 second wait timed out. GetLastError()=%d\n", GetLastError()); fflush(stderr); return ans;
}
}
return ans;
}
typedef HRESULT (__stdcall *app_uid_func)(PCWSTR app_uid);
bool set_app_uid(LPWSTR app_uid) {
// Not available on vista so we have to load the function dynamically
bool ok = false;
HINSTANCE dll = LoadLibraryW(L"Shell32.dll");
if (dll != NULL) {
app_uid_func f = (app_uid_func)GetProcAddress(dll, "SetCurrentProcessExplicitAppUserModelID");
if (f != NULL) ok = f(app_uid) == S_OK;
FreeLibrary(dll); dll = NULL;
}
return ok;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
char buf[257] = {0}, secret[SECRET_SIZE + 1] = {0};
size_t key_size = 0;
HWND parent = NULL;
bool save_dialog = false, multiselect = false, confirm_overwrite = false, only_dirs = false, no_symlinks = false;
unsigned short len = 0;
LPWSTR title = NULL, folder = NULL, filename = NULL, save_path = NULL, echo = NULL, pipename = NULL, default_extension = NULL, app_uid = NULL;
COMDLG_FILTERSPEC *file_types = NULL;
UINT num_file_types = 0;
HANDLE pipe = INVALID_HANDLE_VALUE;
SETBINARY(stdout); SETBINARY(stdin); SETBINARY(stderr);
// The calibre executables call SetDllDirectory, we unset it here just in
// case it interferes with some idiotic shell extension or the other
SetDllDirectory(NULL);
rsbuf = (char*)calloc(65537, sizeof(char));
if(rsbuf == NULL) { PRINTERR("Out of memory!"); return 1; }
while(!feof(stdin)) {
memset(buf, 0, sizeof(buf));
if(!read_bytes(1, buf, true)) { if (feof(stdin)) break; return 1;}
key_size = (size_t)buf[0];
READ(key_size, buf);
if CHECK_KEY("HWND") {
READ(sizeof(HWND), buf);
#pragma warning( push )
#pragma warning( disable : 4312)
if (sizeof(HWND) == 8) parent = (HWND)*((__int64*)buf);
else if (sizeof(HWND) == 4) parent = (HWND)*((__int32*)buf);
else { fprintf(stderr, "Unknown pointer size: %zd", sizeof(HWND)); fflush(stderr); return 1;}
#pragma warning( pop )
}
else if CHECK_KEY("PIPENAME") { READSTR(pipename); pipe = open_named_pipe(pipename); if (pipe == INVALID_HANDLE_VALUE) return 1; }
else if CHECK_KEY("SECRET") { if(!read_bytes(SECRET_SIZE, secret)) return 1; }
else if CHECK_KEY("APP_UID") { READSTR(app_uid) }
else if CHECK_KEY("TITLE") { READSTR(title) }
else if CHECK_KEY("FOLDER") { READSTR(folder) }
else if CHECK_KEY("FILENAME") { READSTR(filename) }
else if CHECK_KEY("SAVE_PATH") { READSTR(save_path) }
else if CHECK_KEY("SAVE_AS") { READBOOL(save_dialog) }
else if CHECK_KEY("MULTISELECT") { READBOOL(multiselect) }
else if CHECK_KEY("CONFIRM_OVERWRITE") { READBOOL(confirm_overwrite) }
else if CHECK_KEY("ONLY_DIRS") { READBOOL(only_dirs) }
else if CHECK_KEY("NO_SYMLINKS") { READBOOL(no_symlinks) }
else if CHECK_KEY("FILE_TYPES") { file_types = read_file_types(&num_file_types); if (file_types == NULL) return 1; }
else if CHECK_KEY("DEFAULT_EXTENSION") { READSTR(default_extension) }
else if CHECK_KEY("ECHO") { READSTR(echo) }
else {
PRINTERR("Unknown key");
return 1;
}
}
if (pipe == INVALID_HANDLE_VALUE) { PRINTERR("No pipename received"); return 1; }
if (secret == NULL) { PRINTERR("No secret received"); return 1; }
if (echo != NULL) {
int echo_sz = 0;
char *echo_buf = to_utf8(echo, &echo_sz);
if (!write_bytes(pipe, SECRET_SIZE+1, secret)) return 1;
return write_bytes(pipe, echo_sz, echo_buf) ? 0 : 1;
}
if (app_uid != NULL) {
// dont check return status as failure is not critical
set_app_uid(app_uid);
}
set_dpi_aware();
return show_dialog(pipe, secret, parent, save_dialog, title, folder, filename, save_path, multiselect, confirm_overwrite, only_dirs, no_symlinks, file_types, num_file_types, default_extension);
}

128
bypy/windows/main.c Normal file
View File

@ -0,0 +1,128 @@
/*
* Copyright 2009 Kovid Goyal
*/
#ifndef UNICODE
#define UNICODE
#endif
#define WINDOWS_LEAN_AND_MEAN
#include<windows.h>
#include<strsafe.h>
static size_t mystrlen(const wchar_t *buf) {
size_t ans = 0;
if (FAILED(StringCbLengthW(buf, 500, &ans))) return 0;
return ans;
}
static int show_error(const wchar_t *preamble, const wchar_t *msg, const int code) {
wchar_t *buf;
buf = (wchar_t*)LocalAlloc(LMEM_ZEROINIT, sizeof(wchar_t)*
(mystrlen(msg) + mystrlen(preamble) + 80));
if (!buf) {
MessageBox(NULL, preamble, NULL, MB_OK|MB_ICONERROR);
return code;
}
MessageBeep(MB_ICONERROR);
wsprintf(buf, L"%s\r\n %s (Error Code: %d)\r\n", preamble, msg, code);
MessageBox(NULL, buf, NULL, MB_OK|MB_ICONERROR);
LocalFree(buf);
return code;
}
static int show_last_error(wchar_t *preamble) {
wchar_t *msg = NULL;
DWORD dw = GetLastError();
int ret;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&msg,
0,
NULL );
ret = show_error(preamble, msg, (int)dw);
if (msg != NULL) LocalFree(msg);
return ret;
}
typedef int (__cdecl *ENTRYPROC)(const char*, const char*, const char*, int);
typedef void (__cdecl *SIMPLEPRINT)(const wchar_t*);
typedef BOOL (*SETDEFAULTDIRS)(DWORD);
static ENTRYPROC entrypoint = NULL;
static SIMPLEPRINT simple_print = NULL;
static HMODULE dll = 0;
static void
load_launcher_dll() {
static wchar_t buf[MAX_PATH]; // Cannot use a zero initializer for the array as it generates an implicit call to memset()
wchar_t *dll_point = NULL;
int i = 0;
DWORD sz = 0;
if ((sz = GetModuleFileNameW(NULL, buf, MAX_PATH)) >= MAX_PATH - 30) {
show_error(L"Installation directory path too long", L"", 1);
return;
}
while (sz > 0) {
if (buf[sz] == L'\\' || buf[sz] == L'/') { dll_point = buf + sz + 1; break; }
sz--;
}
if (dll_point == NULL) {
show_error(L"Executable path has no path separators", L"", 1);
return;
}
wsprintf(dll_point, L"%s\0\0", L"app\\bin");
#if _WIN64
// Restrict the directories from which DLLs can be loaded
// For some reason I cannot determine, using this in 32bit builds causes
// a crash even if no dlls are loaded.
SETDEFAULTDIRS SetDefaultDllDirectories = (SETDEFAULTDIRS)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDefaultDllDirectories");
if (SetDefaultDllDirectories) SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
#endif
if (SetDllDirectoryW(buf) == 0) {
show_last_error(L"Failed to set DLL directory");
return;
}
// Have to load ucrtbase manually first, otherwise loading fails on systems where the
// Universal CRT is not installed.
if (!LoadLibraryW(L"ucrtbase.dll")) {
show_last_error(L"Unable to find ucrtbase.dll. You should install all Windows updates on your computer to get this file.");
return;
}
if (!(dll = LoadLibraryW(L"calibre-launcher.dll"))) {
show_last_error(L"Failed to load: calibre-launcher.dll");
return;
}
if (!(entrypoint = (ENTRYPROC) GetProcAddress(dll, "execute_python_entrypoint"))) {
show_last_error(L"Failed to get the calibre-launcher dll entry point");
return;
}
simple_print = (SIMPLEPRINT) GetProcAddress(dll, "simple_print");
}
int __stdcall start_here() {
int ret = 0;
load_launcher_dll();
if (entrypoint) {
#ifdef GUI_APP
// This should really be returning the value set in the WM_QUIT message, but I cannot be bothered figuring out how to get that.
entrypoint(BASENAME, MODULE, FUNCTION, 1);
#else
ret = entrypoint(BASENAME, MODULE, FUNCTION, 0);
#endif
} else ret = 1;
if (dll != 0) {
FreeLibrary(dll);
dll = 0;
}
ExitProcess(ret);
return ret;
}

View File

@ -0,0 +1,607 @@
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#include <Windows.h>
#include <Shlobj.h>
#include <Shlwapi.h>
#include <Shellapi.h>
#include <Psapi.h>
#include <wchar.h>
#include <stdio.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <easylzma/decompress.h>
#include "XUnzip.h"
#define BUFSIZE 4096
// Error handling {{{
static void show_error(LPCWSTR msg) {
MessageBeep(MB_ICONERROR);
MessageBox(NULL, msg, L"Error", MB_OK|MB_ICONERROR);
}
static void show_detailed_error(LPCWSTR preamble, LPCWSTR msg, int code) {
LPWSTR buf;
buf = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, sizeof(WCHAR)*
(wcslen(msg) + wcslen(preamble) + 80));
_snwprintf_s(buf,
LocalSize(buf) / sizeof(WCHAR), _TRUNCATE,
L"%s\r\n %s (Error Code: %d)\r\n",
preamble, msg, code);
show_error(buf);
LocalFree(buf);
}
static void show_zip_error(LPCWSTR preamble, LPCWSTR msg, ZRESULT code) {
LPWSTR buf;
char msgbuf[1024] = {0};
FormatZipMessage(code, msgbuf, 1024);
buf = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, sizeof(WCHAR)*
(wcslen(preamble) + wcslen(msg) + 1100));
_snwprintf_s(buf,
LocalSize(buf) / sizeof(WCHAR), _TRUNCATE,
L"%s\r\n %s (Error: %S)\r\n",
preamble, msg, msgbuf);
show_error(buf);
LocalFree(buf);
}
static void show_last_error(LPCWSTR preamble) {
WCHAR *msg = NULL;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&msg,
0, NULL );
show_detailed_error(preamble, msg, (int)dw);
}
// }}}
// Load, decompress and extract data {{{
static BOOL load_data(LPVOID *data, DWORD *sz) {
HRSRC rsrc;
HGLOBAL h;
rsrc = FindResourceW(NULL, L"extra", L"extra");
if (rsrc == NULL) { show_last_error(L"Failed to find portable data in exe"); return false; }
h = LoadResource(NULL, rsrc);
if (h == NULL) { show_last_error(L"Failed to load portable data from exe"); return false; }
*data = LockResource(h);
if (*data == NULL) { show_last_error(L"Failed to lock portable data in exe"); return false; }
*sz = SizeofResource(NULL, rsrc);
if (sz == 0) { show_last_error(L"Failed to get size of portable data in exe"); return false; }
return true;
}
static BOOL unzip(HZIP zipf, int nitems, IProgressDialog *pd) {
int i = 0;
ZRESULT res;
ZIPENTRYW ze;
for (i = 0; i < nitems; i++) {
res = GetZipItem(zipf, i, &ze);
if (res != ZR_OK) { show_zip_error(L"Failed to get zip item", L"", res); return false;}
res = UnzipItem(zipf, i, ze.name, 0, ZIP_FILENAME);
if (res != ZR_OK) { CloseZip(zipf); show_zip_error(L"Failed to extract zip item (is your disk full?):", ze.name, res); return false;}
pd->SetLine(2, ze.name, true, NULL);
pd->SetProgress(i, nitems);
}
CloseZip(zipf);
return true;
}
static HANDLE temp_file(LPWSTR name) {
UINT res;
HANDLE h;
res = GetTempFileNameW(L".", L"portable_data", 0, name);
if (res == 0) { show_last_error(L"Failed to create temporary file to decompress portable data"); return INVALID_HANDLE_VALUE; }
h = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) { show_last_error(L"Failed to open temp file to decompress portable data"); }
return h;
}
struct DataStream
{
const unsigned char *in_data;
size_t in_len;
HANDLE out;
IProgressDialog *pd;
};
static int
input_callback(void *ctx, void *buf, size_t * size)
{
size_t rd = 0;
struct DataStream * ds = (struct DataStream *) ctx;
rd = (ds->in_len < *size) ? ds->in_len : *size;
if (rd > 0) {
memcpy(buf, (void*) ds->in_data, rd);
ds->in_data += rd;
ds->in_len -= rd;
}
*size = rd;
return 0;
}
static int output_error_shown = 0;
static size_t
output_callback(void *ctx, const void *buf, size_t size)
{
struct DataStream * ds = (struct DataStream *) ctx;
DWORD written = 0;
if (size > 0) {
if (!WriteFile(ds->out, buf, size, &written, NULL)) {
show_last_error(L"Failed to write uncompressed data to temp file");
output_error_shown = 1;
return 0;
}
written = SetFilePointer(ds->out, 0, NULL, FILE_CURRENT);
ds->pd->SetProgress(written, UNCOMPRESSED_SIZE);
}
return size;
}
static BOOL decompress(LPVOID src, DWORD src_sz, HANDLE out, IProgressDialog *pd) {
elzma_decompress_handle h;
struct DataStream ds;
int rc;
h = elzma_decompress_alloc();
if (h == NULL) { show_error(L"Out of memory"); return false; }
ds.in_data = (unsigned char*)src;
ds.in_len = src_sz;
ds.out = out;
ds.pd = pd;
rc = elzma_decompress_run(h, input_callback, (void *) &ds, output_callback,
(void *) &ds, ELZMA_lzip);
if (rc != ELZMA_E_OK) {
if (!output_error_shown) show_detailed_error(L"Failed to decompress portable data", L"", rc);
elzma_decompress_free(&h);
return false;
}
elzma_decompress_free(&h);
return true;
}
static BOOL extract(LPVOID cdata, DWORD csz) {
HANDLE h;
WCHAR tempnam[MAX_PATH+1] = {0};
BOOL ret = true;
HZIP zipf;
ZIPENTRYW ze;
ZRESULT res;
int nitems;
HRESULT hr;
IProgressDialog *pd = NULL;
hr = CoCreateInstance(CLSID_ProgressDialog, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pd));
if (FAILED(hr)) { show_error(L"Failed to create progress dialog"); return false; }
pd->SetTitle(L"Extracting Calibre Portable");
pd->SetLine(1, L"Decompressing data...", true, NULL);
h = temp_file(tempnam);
if (h == INVALID_HANDLE_VALUE) return false;
pd->StartProgressDialog(NULL, NULL, PROGDLG_NORMAL | PROGDLG_AUTOTIME | PROGDLG_NOCANCEL, NULL);
if (!decompress(cdata, csz, h, pd)) { ret = false; goto end; }
SetFilePointer(h, 0, NULL, FILE_BEGIN);
zipf = OpenZip(h, 0, ZIP_HANDLE);
if (zipf == 0) { show_last_error(L"Failed to open zipped portable data"); ret = false; goto end; }
res = GetZipItem(zipf, -1, &ze);
if (res != ZR_OK) { show_zip_error(L"Failed to get count of items in portable data", L"", res); ret = false; goto end;}
nitems = ze.index;
pd->SetLine(1, L"Copying files...", true, NULL);
if (!unzip(zipf, nitems, pd)) { ret = false; goto end; }
end:
pd->StopProgressDialog();
pd->Release();
CloseHandle(h);
DeleteFile(tempnam);
return ret;
}
// }}}
// Find calibre portable directory and install/upgrade into it {{{
static BOOL directory_exists( LPCWSTR path )
{
if( _waccess_s( path, 0 ) == 0 )
{
struct _stat status;
_wstat( path, &status );
return (status.st_mode & S_IFDIR) != 0;
}
return FALSE;
}
static BOOL file_exists( LPCWSTR path )
{
if( _waccess_s( path, 0 ) == 0 )
{
struct _stat status;
_wstat( path, &status );
return (status.st_mode & S_IFREG) != 0;
}
return FALSE;
}
static LPWSTR get_directory_from_user() {
WCHAR name[MAX_PATH+1] = {0};
LPWSTR path = NULL;
PIDLIST_ABSOLUTE ret;
path = (LPWSTR)calloc(2*MAX_PATH, sizeof(WCHAR));
if (path == NULL) { show_error(L"Out of memory"); return NULL; }
int image = 0;
BROWSEINFO bi = { NULL, NULL, name,
L"Select the folder where you want to install or update Calibre Portable",
BIF_RETURNONLYFSDIRS | BIF_DONTGOBELOWDOMAIN | BIF_USENEWUI,
NULL, NULL, image };
ret = SHBrowseForFolder(&bi);
if (ret == NULL) {
return NULL;
}
if (!SHGetPathFromIDList(ret, path)) {
show_detailed_error(L"The selected folder is not valid: ", name, 0);
return NULL;
}
return path;
}
static bool is_dots(LPCWSTR name) {
return wcscmp(name, L".") == 0 || wcscmp(name, L"..") == 0;
}
static bool rmtree(LPCWSTR path) {
SHFILEOPSTRUCTW op;
WCHAR buf[4*MAX_PATH + 2] = {0};
if (GetFullPathName(path, 4*MAX_PATH, buf, NULL) == 0) return false;
op.hwnd = NULL;
op.wFunc = FO_DELETE;
op.pFrom = buf;
op.pTo = NULL;
op.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMMKDIR;
op.fAnyOperationsAborted = false;
op.hNameMappings = NULL;
op.lpszProgressTitle = NULL;
return SHFileOperationW(&op) == 0;
}
static BOOL find_portable_dir(LPCWSTR base, LPWSTR *result, BOOL *existing) {
WCHAR buf[4*MAX_PATH] = {0};
_snwprintf_s(buf, 4*MAX_PATH, _TRUNCATE, L"%s\\calibre-portable.exe", base);
*existing = true;
if (file_exists(buf)) {
*result = _wcsdup(base);
if (*result == NULL) { show_error(L"Out of memory"); return false; }
return true;
}
WIN32_FIND_DATA fdFile;
HANDLE hFind = NULL;
_snwprintf_s(buf, 4*MAX_PATH, _TRUNCATE, L"%s\\*", base);
if((hFind = FindFirstFileEx(buf, FindExInfoStandard, &fdFile, FindExSearchLimitToDirectories, NULL, 0)) != INVALID_HANDLE_VALUE) {
do {
if(is_dots(fdFile.cFileName)) continue;
if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
_snwprintf_s(buf, 4*MAX_PATH, _TRUNCATE, L"%s\\%s\\calibre-portable.exe", base, fdFile.cFileName);
if (file_exists(buf)) {
*result = _wcsdup(buf);
if (*result == NULL) { show_error(L"Out of memory"); return false; }
PathRemoveFileSpec(*result);
FindClose(hFind);
return true;
}
}
} while(FindNextFile(hFind, &fdFile));
FindClose(hFind);
}
*existing = false;
_snwprintf_s(buf, 4*MAX_PATH, _TRUNCATE, L"%s\\Calibre Portable", base);
if (!CreateDirectory(buf, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
show_last_error(L"Failed to create Calibre Portable folder");
return false;
}
*result = _wcsdup(buf);
if (*result == NULL) { show_error(L"Out of memory"); return false; }
return true;
}
static LPWSTR make_unpack_dir() {
WCHAR buf[4*MAX_PATH] = {0};
LPWSTR ans = NULL;
if (directory_exists(L"_unpack_calibre_portable"))
rmtree(L"_unpack_calibre_portable");
if (!CreateDirectory(L"_unpack_calibre_portable", NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
show_last_error(L"Failed to create temporary folder to unpack into");
return ans;
}
if (!GetFullPathName(L"_unpack_calibre_portable", 4*MAX_PATH, buf, NULL)) {
show_last_error(L"Failed to resolve path");
return NULL;
}
ans = _wcsdup(buf);
if (ans == NULL) show_error(L"Out of memory");
return ans;
}
static BOOL move_program() {
if (MoveFileEx(L"Calibre Portable\\calibre-portable.exe",
L"..\\calibre-portable.exe", MOVEFILE_REPLACE_EXISTING) == 0) {
show_last_error(L"Failed to move calibre-portable.exe, make sure calibre is not running");
return false;
}
if (directory_exists(L"..\\Calibre")) {
if (!rmtree(L"..\\Calibre")) {
show_error(L"Failed to delete the Calibre program folder. Make sure calibre is not running.");
return false;
}
}
if (MoveFileEx(L"Calibre Portable\\Calibre", L"..\\Calibre", 0) == 0) {
Sleep(4000); // Sleep and try again
if (MoveFileEx(L"Calibre Portable\\Calibre", L"..\\Calibre", 0) == 0) {
show_last_error(L"Failed to move calibre program folder. This is usually caused by an antivirus program or a file sync program like DropBox. Turn them off temporarily and try again. Underlying error: ");
return false;
}
}
if (!directory_exists(L"..\\Calibre Library")) {
MoveFileEx(L"Calibre Portable\\Calibre Library", L"..\\Calibre Library", 0);
}
if (!directory_exists(L"..\\Calibre Settings")) {
MoveFileEx(L"Calibre Portable\\Calibre Settings", L"..\\Calibre Settings", 0);
}
return true;
}
// }}}
static BOOL ensure_not_running() {
DWORD processes[4096], needed, num;
unsigned int i;
WCHAR name[4*MAX_PATH] = L"<unknown>";
HANDLE h;
DWORD len;
LPWSTR fname = NULL;
if ( !EnumProcesses( processes, sizeof(processes), &needed ) ) {
return true;
}
num = needed / sizeof(DWORD);
for (i = 0; i < num; i++) {
if (processes[i] == 0) continue;
h = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, processes[i] );
if (h != NULL) {
len = GetProcessImageFileNameW(h, name, 4*MAX_PATH);
CloseHandle(h);
if (len != 0) {
name[len] = 0;
fname = PathFindFileName(name);
if (wcscmp(fname, L"calibre.exe") == 0) {
show_error(L"Calibre appears to be running on your computer. Please quit it before trying to install Calibre Portable.");
return false;
}
}
}
}
return true;
}
static void launch_calibre() {
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if (CreateProcess(_wcsdup(L"calibre-portable.exe"), NULL,
NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP,
NULL, NULL, &si, &pi)
== 0) {
show_last_error(L"Failed to launch calibre portable");
}
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
void makedirs(LPWSTR path) {
WCHAR *p = path;
while (*p) {
if ((*p == L'\\' || *p == L'/') && p != path && *(p-1) != L':') {
*p = 0;
CreateDirectory(path, NULL);
*p = L'\\';
}
p++;
}
CreateDirectory(path, NULL);
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
(void)hPrevInstance; (void)pCmdLine; (void)nCmdShow;
LPVOID cdata = NULL;
DWORD csz = 0;
int ret = 1, argc;
HRESULT hr;
LPWSTR tgt = NULL, dest = NULL, *argv, unpack_dir = NULL;
BOOL existing = false, launch = false, automated = false;
WCHAR buf[4*MAX_PATH] = {0}, mb_msg[4*MAX_PATH] = {0}, fdest[4*MAX_PATH] = {0};
if (!load_data(&cdata, &csz)) return ret;
hr = CoInitialize(NULL);
if (FAILED(hr)) { show_error(L"Failed to initialize COM"); return ret; }
// Get the target directory for installation
argv = CommandLineToArgvW(GetCommandLine(), &argc);
if (argv == NULL) { show_last_error(L"Failed to get command line"); return ret; }
if (argc > 1) {
tgt = argv[1];
automated = true;
if (!directory_exists(tgt)) {
if (GetFullPathName(tgt, MAX_PATH*4, fdest, NULL) == 0) {
show_last_error(L"Failed to resolve target folder");
goto end;
}
makedirs(fdest);
}
} else {
tgt = get_directory_from_user();
if (tgt == NULL) goto end;
}
if (!directory_exists(tgt)) {
show_detailed_error(L"The specified directory does not exist: ",
tgt, 1);
goto end;
}
// Ensure the path to Calibre Portable is not too long
do {
if (!find_portable_dir(tgt, &dest, &existing)) goto end;
if (GetFullPathName(dest, MAX_PATH*4, fdest, NULL) == 0) {
show_last_error(L"Failed to resolve target folder");
goto end;
}
free(dest); dest = NULL;
if (wcslen(fdest) > 58) {
_snwprintf_s(buf, 4*MAX_PATH, _TRUNCATE,
L"Path to Calibre Portable (%s) too long. Must be less than 59 characters.", fdest);
if (!existing) RemoveDirectory(fdest);
show_error(buf);
tgt = get_directory_from_user();
if (tgt == NULL) goto end;
}
} while (wcslen(fdest) > 58);
// Confirm the user wants to upgrade
if (existing && !automated) {
_snwprintf_s(mb_msg, 4*MAX_PATH, _TRUNCATE,
L"An existing install of Calibre Portable was found at %s. Do you want to upgrade it?",
fdest);
if (MessageBox(NULL, mb_msg,
L"Upgrade Calibre Portable?", MB_ICONEXCLAMATION | MB_YESNO | MB_TOPMOST) != IDYES)
goto end;
}
if (existing) {
if (!ensure_not_running()) goto end;
}
// Make a temp dir to unpack into
if (!SetCurrentDirectoryW(fdest)) { show_detailed_error(L"Failed to change to unzip directory: ", fdest, 0); goto end; }
if ( (unpack_dir = make_unpack_dir()) == NULL ) goto end;
if (!SetCurrentDirectoryW(unpack_dir)) { show_detailed_error(L"Failed to change to unpack directory: ", fdest, 0); goto end; }
// Extract files
if (!extract(cdata, csz)) goto end;
// Move files from temp dir to the install dir
if (!move_program()) goto end;
ret = 0;
if (!automated) {
_snwprintf_s(mb_msg, 4*MAX_PATH, _TRUNCATE,
L"Calibre Portable successfully installed to %s. Launch calibre?",
fdest);
launch = MessageBox(NULL, mb_msg,
L"Success", MB_ICONINFORMATION | MB_YESNO | MB_TOPMOST) == IDYES;
}
end:
if (unpack_dir != NULL) { SetCurrentDirectoryW(L".."); rmtree(unpack_dir); free(unpack_dir); }
CoUninitialize();
if (launch) launch_calibre();
return ret;
}

154
bypy/windows/portable.c Normal file
View File

@ -0,0 +1,154 @@
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#include <windows.h>
#include <tchar.h>
#include <wchar.h>
#include <stdio.h>
#define BUFSIZE 4096
void show_error(LPCTSTR msg) {
MessageBeep(MB_ICONERROR);
MessageBox(NULL, msg, _T("Error"), MB_OK|MB_ICONERROR);
}
void show_detailed_error(LPCTSTR preamble, LPCTSTR msg, int code) {
LPTSTR buf;
buf = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*
(_tcslen(msg) + _tcslen(preamble) + 80));
_sntprintf_s(buf,
LocalSize(buf) / sizeof(TCHAR), _TRUNCATE,
_T("%s\r\n %s (Error Code: %d)\r\n"),
preamble, msg, code);
show_error(buf);
LocalFree(buf);
}
void show_last_error_crt(LPCTSTR preamble) {
TCHAR buf[BUFSIZE];
int err = 0;
_get_errno(&err);
_tcserror_s(buf, BUFSIZE, err);
show_detailed_error(preamble, buf, err);
}
void show_last_error(LPCTSTR preamble) {
TCHAR *msg = NULL;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&msg,
0, NULL );
show_detailed_error(preamble, msg, (int)dw);
}
LPTSTR get_app_dir() {
LPTSTR buf, buf2, buf3;
DWORD sz;
TCHAR drive[4] = _T("\0\0\0");
errno_t err;
buf = (LPTSTR)calloc(BUFSIZE, sizeof(TCHAR));
buf2 = (LPTSTR)calloc(BUFSIZE, sizeof(TCHAR));
buf3 = (LPTSTR)calloc(BUFSIZE, sizeof(TCHAR));
sz = GetModuleFileName(NULL, buf, BUFSIZE);
if (sz == 0 || sz > BUFSIZE-1) {
show_error(_T("Failed to get path to calibre-portable.exe"));
ExitProcess(1);
}
err = _tsplitpath_s(buf, drive, 4, buf2, BUFSIZE, NULL, 0, NULL, 0);
if (err != 0) {
show_last_error_crt(_T("Failed to split path to calibre-portable.exe"));
ExitProcess(1);
}
_sntprintf_s(buf3, BUFSIZE-1, _TRUNCATE, _T("%s%s"), drive, buf2);
free(buf); free(buf2);
return buf3;
}
void launch_calibre(LPCTSTR exe, LPCTSTR config_dir) {
DWORD dwFlags=0;
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL fSuccess;
if (! SetEnvironmentVariable(_T("CALIBRE_CONFIG_DIRECTORY"), config_dir)) {
show_last_error(_T("Failed to set environment variables"));
ExitProcess(1);
}
if (! SetEnvironmentVariable(_T("CALIBRE_PORTABLE_BUILD"), exe)) {
show_last_error(_T("Failed to set environment variables"));
ExitProcess(1);
}
dwFlags = CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
fSuccess = CreateProcess(exe, NULL,
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
dwFlags, // Creation flags http://msdn.microsoft.com/en-us/library/ms684863(v=vs.85).aspx
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure
);
if (fSuccess == 0) {
show_last_error(_T("Failed to launch the calibre program"));
}
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
LPTSTR app_dir, config_dir, exe;
app_dir = get_app_dir();
config_dir = (LPTSTR)calloc(BUFSIZE, sizeof(TCHAR));
exe = (LPTSTR)calloc(BUFSIZE, sizeof(TCHAR));
_sntprintf_s(config_dir, BUFSIZE, _TRUNCATE, _T("%sCalibre Settings"), app_dir);
_sntprintf_s(exe, BUFSIZE, _TRUNCATE, _T("%sCalibre\\calibre.exe"), app_dir);
launch_calibre(exe, config_dir);
free(app_dir); free(config_dir); free(exe);
return 0;
}

114
bypy/windows/site.py Normal file
View File

@ -0,0 +1,114 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import sys
import os
import imp
class PydImporter(object):
__slots__ = ('items', 'description')
def __init__(self):
self.items = None
self.description = ('.pyd', 'rb', imp.C_EXTENSION)
def find_module(self, fullname, path=None):
if self.items is None:
dlls_dir = os.path.join(sys.app_dir, 'app', 'bin')
items = self.items = {}
for x in os.listdir(dlls_dir):
lx = x.lower()
if lx.endswith(b'.pyd'):
items[lx[:-4]] = os.path.abspath(os.path.join(dlls_dir, x))
return self if fullname.lower() in self.items else None
def load_module(self, fullname):
m = sys.modules.get(fullname)
if m is not None:
return m
try:
path = self.items[fullname.lower()]
except KeyError:
raise ImportError(
'The native code module %s seems to have disappeared from self.items'
% fullname
)
package, name = fullname.rpartition(b'.')[::2]
m = imp.load_module(
fullname, None, path, self.description
) # This inserts the module into sys.modules itself
m.__loader__ = self
m.__package__ = package or None
return m
def abs__file__():
"""Set all module __file__ attribute to an absolute path"""
for m in sys.modules.values():
if hasattr(m, '__loader__'):
continue # don't mess with a PEP 302-supplied __file__
try:
m.__file__ = os.path.abspath(m.__file__)
except AttributeError:
continue
def aliasmbcs():
import locale, codecs
enc = locale.getdefaultlocale()[1]
if enc.startswith('cp'): # "cp***" ?
try:
codecs.lookup(enc)
except LookupError:
import encodings
encodings._cache[enc] = encodings._unknown
encodings.aliases.aliases[enc] = 'mbcs'
def add_calibre_vars():
sys.new_app_layout = 1
sys.resources_location = os.path.join(sys.app_dir, 'app', 'resources')
sys.extensions_location = os.path.join(sys.app_dir, 'app', 'bin')
dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
if dv and os.path.exists(dv):
sys.path.insert(0, os.path.abspath(dv))
def run_entry_point():
bname, mod, func = sys.calibre_basename, sys.calibre_module, sys.calibre_function
sys.argv[0] = bname + '.exe'
pmod = __import__(mod, fromlist=[1], level=0)
return getattr(pmod, func)()
def main():
sys.frozen = 'windows_exe'
sys.setdefaultencoding('utf-8')
aliasmbcs()
sys.meta_path.insert(0, PydImporter())
sys.path_importer_cache.clear()
import linecache
def fake_getline(filename, lineno, module_globals=None):
return ''
linecache.orig_getline = linecache.getline
linecache.getline = fake_getline
abs__file__()
add_calibre_vars()
# Needed to bypass meaningless check in pywintypes.py
sys.path.append(os.path.join(sys.app_dir, 'app', 'bin'))
return run_entry_point()

42
bypy/windows/template.rc Normal file
View File

@ -0,0 +1,42 @@
#include <windows.h>
#define VER_FILEVERSION {file_version}
#define VER_FILEVERSION_STR "{file_version_str}"
#define VER_PRODUCTVERSION {product_version}
#define VER_PRODUCTVERSION_STR "{product_version_str}"
#define VER_DEBUG 0
1 VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS VER_DEBUG
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_{file_type}
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "calibre-ebook.com"
VALUE "FileDescription", "{file_description}"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "{internal_name}"
VALUE "LegalCopyright", "{legal_copyright}"
VALUE "LegalTrademarks", "{legal_trademarks}"
VALUE "OriginalFilename", "{original_filename}"
VALUE "ProductName", "{product_name}"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
1 ICON "{icon}"

409
bypy/windows/util.c Normal file
View File

@ -0,0 +1,409 @@
/*
* Copyright 2009 Kovid Goyal
*/
#define UNICODE
#define _WIN32_WINNT 0x0502
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#include <Python.h>
#include <stdio.h>
#include <stdlib.h>
#include <Shellapi.h>
#include <delayimp.h>
#include <io.h>
#include <fcntl.h>
#define arraysz(x) (sizeof((x))/sizeof((x)[0]))
static int GUI_APP = 0;
static char python_dll[] = PYDLL;
void set_gui_app(int yes) { GUI_APP = yes; }
int calibre_show_python_error(const wchar_t *preamble, int code);
static int _show_error(const wchar_t *preamble, const wchar_t *msg, const int code) {
static wchar_t buf[4096];
static char utf8_buf[4096] = {0};
int n = WideCharToMultiByte(CP_UTF8, 0, preamble, -1, utf8_buf, sizeof(utf8_buf) - 1, NULL, NULL);
if (n > 0) fprintf(stderr, "%s\r\n ", utf8_buf);
n = WideCharToMultiByte(CP_UTF8, 0, msg, -1, utf8_buf, sizeof(utf8_buf) - 1, NULL, NULL);
if (n > 0) fprintf(stderr, "%s (Error Code: %d)\r\n ", utf8_buf, code);
fflush(stderr);
if (GUI_APP) {
_snwprintf_s(buf, arraysz(buf), _TRUNCATE, L"%ls\r\n %ls (Error Code: %d)\r\n", preamble, msg, code);
MessageBeep(MB_ICONERROR);
MessageBox(NULL, buf, NULL, MB_OK|MB_ICONERROR);
}
return code;
}
int show_last_error_crt(wchar_t *preamble) {
wchar_t buf[1000];
int err = 0;
_get_errno(&err);
_wcserror_s(buf, 1000, err);
return _show_error(preamble, buf, err);
}
int show_last_error(wchar_t *preamble) {
wchar_t *msg = NULL;
DWORD dw = GetLastError();
int ret;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&msg,
0,
NULL );
ret = _show_error(preamble, msg, (int)dw);
if (msg != NULL) LocalFree(msg);
return ret;
}
static char app_dir[MAX_PATH] = {0};
static wchar_t dll_dir[MAX_PATH] = {0};
static wchar_t qt_prefix_dir[MAX_PATH] = {0};
static char program_name[MAX_PATH] = {0};
static wchar_t w_program_name[MAX_PATH] = {0};
static wchar_t w_app_dir[MAX_PATH] = {0};
#if PY_VERSION_MAJOR >= 3
static wchar_t python_path[MAX_PATH] = {0};
#else
static char python_path[MAX_PATH] = {0};
#endif
static void
get_app_dir(void) {
char drive[4] = "\0\0\0";
DWORD sz; errno_t err;
char buf[MAX_PATH] = {0};
sz = GetModuleFileNameA(NULL, program_name, MAX_PATH);
if (sz >= MAX_PATH-1) ExitProcess(_show_error(L"Installation directory path too long", L"", 1));
err = _splitpath_s(program_name, drive, 4, buf, MAX_PATH, NULL, 0, NULL, 0);
if (err != 0) ExitProcess(show_last_error_crt(L"Failed to find application directory"));
_snprintf_s(app_dir, MAX_PATH, _TRUNCATE, "%s%s", drive, buf);
}
static void
get_app_dirw(void) {
wchar_t buf[MAX_PATH] = {0};
wchar_t drive[4] = L"\0\0\0";
DWORD sz; errno_t err;
sz = GetModuleFileNameW(NULL, w_program_name, MAX_PATH);
if (sz >= MAX_PATH-1) ExitProcess(_show_error(L"Installation directory path too long", L"", 1));
err = _wsplitpath_s(w_program_name, drive, 4, buf, MAX_PATH, NULL, 0, NULL, 0);
if (err != 0) ExitProcess(show_last_error_crt(L"Failed to find application directory"));
_snwprintf_s(w_app_dir, MAX_PATH, _TRUNCATE, L"%ls%ls", drive, buf);
}
static void
get_install_locations(void) {
get_app_dir();
get_app_dirw();
_snwprintf_s(qt_prefix_dir, MAX_PATH-1, _TRUNCATE, L"%ls\\app", w_app_dir);
_wputenv_s(L"CALIBRE_QT_PREFIX", qt_prefix_dir);
_snwprintf_s(dll_dir, MAX_PATH-1, _TRUNCATE, L"%ls\\app\\bin", w_app_dir);
#if PY_VERSION_MAJOR >= 3
_snwprintf_s(python_path, MAX_PATH-1, _TRUNCATE, L"%ls\\app\\pylib.zip", w_app_dir);
#else
_snprintf_s(python_path, MAX_PATH-1, _TRUNCATE, "%s\\app\\pylib.zip", app_dir);
#endif
}
static void
load_python_dll() {
get_install_locations();
if (FAILED(__HrLoadAllImportsForDll(python_dll)))
ExitProcess(_show_error(L"Failed to delay load the python dll", L"", 1));
}
const static wchar_t out_of_memory[] = L"Out of memory";
static void
setup_stream(const char *name, const char *errors, UINT cp) {
PyObject *stream;
char buf[128] = {0};
if (cp == CP_UTF8) _snprintf_s(buf, 100, _TRUNCATE, "%s", "utf-8");
else if (cp == CP_UTF7) _snprintf_s(buf, 100, _TRUNCATE, "%s", "utf-7");
else _snprintf_s(buf, 100, _TRUNCATE, "cp%d", cp);
stream = PySys_GetObject((char*)name);
if (!PyFile_SetEncodingAndErrors(stream, buf, (char*)errors))
ExitProcess(calibre_show_python_error(L"Failed to set stream encoding", 1));
}
UINT
setup_streams() {
UINT code_page = GetConsoleOutputCP();
SetConsoleOutputCP(CP_UTF8);
_putenv_s("PYTHONIOENCODING", "UTF-8");
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stderr), _O_BINARY);
if (!GUI_APP) { // Remove buffering
setvbuf(stdin, NULL, _IONBF, 2);
setvbuf(stdout, NULL, _IONBF, 2);
setvbuf(stderr, NULL, _IONBF, 2);
}
//printf("input cp: %d output cp: %d\r\n", GetConsoleCP(), GetConsoleOutputCP());
setup_stream("stdin", "strict", GetConsoleCP());
setup_stream("stdout", "strict", CP_UTF8);
setup_stream("stderr", "strict", CP_UTF8);
return code_page;
}
UINT
initialize_interpreter(const char *basename, const char *module, const char *function) {
HMODULE dll;
int *flag, i, argc;
wchar_t **wargv;
PyObject *argv, *v;
char *dummy_argv[1] = {""};
dll = GetModuleHandleA(python_dll);
if (!dll) ExitProcess(show_last_error(L"Failed to get python dll handle"));
flag = (int*)GetProcAddress(dll, "Py_OptimizeFlag");
if (!flag) ExitProcess(_show_error(L"Failed to get optimize flag", L"", 1));
*flag = 2;
flag = (int*)GetProcAddress(dll, "Py_NoSiteFlag");
if (!flag) ExitProcess(_show_error(L"Failed to get no_site flag", L"", 1));
*flag = 1;
flag = (int*)GetProcAddress(dll, "Py_DontWriteBytecodeFlag");
if (!flag) ExitProcess(_show_error(L"Failed to get no_bytecode flag", L"", 1));
*flag = 1;
flag = (int*)GetProcAddress(dll, "Py_IgnoreEnvironmentFlag");
if (!flag) ExitProcess(_show_error(L"Failed to get ignore_environment flag", L"", 1));
*flag = 1;
flag = (int*)GetProcAddress(dll, "Py_NoUserSiteDirectory");
if (!flag) ExitProcess(_show_error(L"Failed to get user_site flag", L"", 1));
*flag = 1;
flag = (int*)GetProcAddress(dll, "Py_HashRandomizationFlag");
if (!flag) ExitProcess(_show_error(L"Failed to get hash randomization flag", L"", 1));
*flag = 1;
flag = (int*)GetProcAddress(dll, "Py_VerboseFlag");
if (!flag) ExitProcess(_show_error(L"Failed to get verbose flag", L"", 1));
//*flag = 1;
flag = (int*)GetProcAddress(dll, "Py_DebugFlag");
if (!flag) ExitProcess(_show_error(L"Failed to get debug flag", L"", 1));
//*flag = 1;
#if PY_VERSION_MAJOR >= 3
Py_SetProgramName(w_program_name);
Py_SetPythonHome(w_app_dir);
#else
Py_SetProgramName(program_name);
Py_SetPythonHome(app_dir);
#endif
//printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath());
Py_Initialize();
UINT code_page = setup_streams();
PySys_SetArgv(1, dummy_argv);
//printf("Path after Py_Initialize(): %s\r\n\n", Py_GetPath());
PySys_SetPath(python_path);
//printf("Path set by me: %s\r\n\n", path);
PySys_SetObject("gui_app", PyBool_FromLong((long)GUI_APP));
PySys_SetObject("app_dir", PyUnicode_FromWideChar(w_app_dir, wcslen(w_app_dir)));
PySys_SetObject("calibre_basename", PyBytes_FromString(basename));
PySys_SetObject("calibre_module", PyBytes_FromString(module));
PySys_SetObject("calibre_function", PyBytes_FromString(function));
wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
if (wargv == NULL) ExitProcess(show_last_error(L"Failed to get command line"));
argv = PyList_New(argc);
if (argv == NULL) ExitProcess(_show_error(out_of_memory, L"", 1));
for (i = 0; i < argc; i++) {
v = PyUnicode_FromWideChar(wargv[i], wcslen(wargv[i]));
if (v == NULL) ExitProcess(_show_error(out_of_memory, L"", 1));
PyList_SetItem(argv, i, v);
}
PySys_SetObject("argv", argv);
return code_page;
}
static const wchar_t*
pyobject_to_wchar(PyObject *o) {
PyObject *t = NULL;
size_t s;
static wchar_t ans[4096];
if (!PyUnicode_Check(o)) {
t = PyUnicode_FromEncodedObject(o, NULL, "replace");
if (t == NULL) return NULL;
}
s = PyUnicode_AsWideChar((PyUnicodeObject*)(t ? t : o), ans, arraysz(ans)-1);
Py_XDECREF(t);
if (s >= 0) ans[s] = 0;
else ans[s] = 0;
return ans;
}
int pyobject_to_int(PyObject *res) {
int ret; PyObject *tmp;
tmp = PyNumber_Int(res);
if (tmp == NULL) ret = (PyObject_IsTrue(res)) ? 1 : 0;
else ret = (int)PyInt_AS_LONG(tmp);
return ret;
}
int handle_sysexit(PyObject *e) {
PyObject *code;
code = PyObject_GetAttrString(e, "code");
if (!code) return 0;
if (!PyInt_Check(code)) {
PyObject_Print(code, stderr, Py_PRINT_RAW);
fflush(stderr);
}
return pyobject_to_int(code);
}
int calibre_show_python_error(const wchar_t *preamble, int code) {
PyObject *exc, *val, *tb, *str, **system_exit;
HMODULE dll;
int ret, issysexit = 0; const wchar_t *i;
if (!PyErr_Occurred()) return code;
dll = GetModuleHandleA(python_dll);
if (!dll) ExitProcess(show_last_error(L"Failed to get python dll handle"));
system_exit = (PyObject**)GetProcAddress(dll, "PyExc_SystemExit");
issysexit = PyErr_ExceptionMatches(*system_exit);
PyErr_Fetch(&exc, &val, &tb);
if (exc != NULL) {
PyErr_NormalizeException(&exc, &val, &tb);
if (issysexit) {
return (val) ? handle_sysexit(val) : 0;
}
if (val != NULL) {
str = PyObject_Unicode(val);
if (str == NULL) {
PyErr_Clear();
str = PyObject_Str(val);
}
i = pyobject_to_wchar(str);
ret = _show_error(preamble, (i==NULL)?out_of_memory:i, code);
if (tb != NULL) {
PyErr_Restore(exc, val, tb);
PyErr_Print();
}
return ret;
}
}
return _show_error(preamble, L"", code);
}
void redirect_out_stream(FILE *stream) {
FILE *f = NULL;
errno_t err;
err = freopen_s(&f, "NUL", "wt", stream);
if (err != 0) {
ExitProcess(show_last_error_crt(L"Failed to redirect stdout/stderr to NUL. This indicates a corrupted Windows install.\r\n You should contact Microsoft for assistance and/or follow the steps described here:\r\n http://bytes.com/topic/net/answers/264804-compile-error-null-device-missing"));
}
}
static void
null_invalid_parameter_handler(
const wchar_t * expression,
const wchar_t * function,
const wchar_t * file,
unsigned int line,
uintptr_t pReserved
) {
// The python runtime expects various system calls with invalid parameters
// to return errors instead of aborting the program. So get the windows CRT
// to do that.
}
__declspec(dllexport) int __cdecl
simple_print(const wchar_t *msg) {
int n = wprintf(L"%ls", msg); fflush(stdout);
return n;
}
__declspec(dllexport) int __cdecl
execute_python_entrypoint(const char *basename, const char *module, const char *function, int is_gui_app) {
PyObject *site, *main, *res;
int ret = 0;
// Prevent Windows' idiotic error dialog popups when various win32 api functions fail
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
if (is_gui_app) {
// Redirect stdout and stderr to NUL so that python does not fail writing to them
redirect_out_stream(stdout);
redirect_out_stream(stderr);
}
set_gui_app(is_gui_app);
// Disable the invalid parameter handler
_set_invalid_parameter_handler(null_invalid_parameter_handler);
load_python_dll();
UINT code_page = initialize_interpreter(basename, module, function);
site = PyImport_ImportModule("site");
if (site == NULL)
ret = calibre_show_python_error(L"Failed to import site module", 1);
else {
Py_INCREF(site);
main = PyObject_GetAttrString(site, "main");
if (main == NULL || !PyCallable_Check(main))
ret = calibre_show_python_error(L"site module has no main function", 1);
else {
Py_INCREF(main);
res = PyObject_CallObject(main, NULL);
if (res == NULL)
ret = calibre_show_python_error(L"Python function terminated unexpectedly", 1);
else {
#if PY_VERSION_MAJOR < 3
if (PyInt_Check(res)) {
ret = PyInt_AS_LONG(res);
}
#else
if (PyLong_Check(res)) {
ret = PyLong_AsLong(res);
}
#endif
Py_DECREF(res);
}
}
}
PyErr_Clear();
Py_Finalize();
if (code_page != CP_UTF8) SetConsoleOutputCP(code_page);
/* printf("111111111111 returning: %d\r\n", ret); */
return ret;
}

View File

@ -0,0 +1,206 @@
<?xml version='1.0' encoding='utf-8'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi' xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
>
<Product Name='{app}{x64}' Id='*' UpgradeCode='{upgrade_code}' Language='1033' Codepage='1252' Version='{version}' Manufacturer='Kovid Goyal'>
<Package Id='*' Keywords='Installer' Description="{app} Installer"
Comments='{app} is a registered trademark of Kovid Goyal' Manufacturer='Kovid Goyal'
InstallerVersion='300' Languages='1033' Compressed='yes'
SummaryCodepage='1252' />
<!-- Disable creation of system restore points on calibre installs. Speeds
up the install. We dont need system restore since we dont install any
system DLLs/components anyway (apart from start menu entries) -->
<Property Id="MSIFASTINSTALL" Value="3" />
<Media Id="1" Cabinet="{app}.cab" CompressionLevel="{compression}" EmbedCab="yes" />
<!-- The following line ensures that DLLs are replaced even if
their version is the same as before or they dont have versions.
Microsoft's brain dead installer will otherwise use file dates to
determine whether to install a file or not. Simply not robust. And
since we dont install any system files whatsoever, we can never replace
a system file with an older version. This way the calibre install
should always result in a consistent set of files being present in the
installation folder, though of course, with Microsoft there are no
guarantees of anything. -->
<Property Id='REINSTALLMODE' Value='amus'/>
<Upgrade Id="{upgrade_code}">
<UpgradeVersion Maximum="{version}"
IncludeMaximum="yes"
OnlyDetect="no"
Language="1033"
MigrateFeatures="yes"
Property="OLDPRODUCTFOUND"/>
<UpgradeVersion Minimum="{version}"
IncludeMinimum="no"
OnlyDetect="yes"
Language="1033"
Property="NEWPRODUCTFOUND"/>
</Upgrade>
<CustomAction Id="PreventDowngrading" Error="Newer version of {app} already installed. If you want to downgrade you must uninstall {app} first."/>
<Property Id="APPLICATIONFOLDER">
<RegistrySearch Id='calibreInstDir' Type='raw'
Root='HKLM' Key="Software\{app}{x64}\Installer" Name="InstallPath" />
</Property>
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='{ProgramFilesFolder}' Name='PFiles'>
<!-- The name must be calibre on 32 bit to ensure
that the component guids dont change compared to previous msis.
However, on 64 bit it must be Calibre2 otherwise by default it
will install to C:\Program Files\calibre -->
<Directory Id='APPLICATIONFOLDER' Name="{appfolder}" />
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="{app}{x64} - E-book Management"/>
</Directory>
<Directory Id="DesktopFolder" Name="Desktop"/>
</Directory>
<Icon Id="main_icon" SourceFile="{main_icon}"/>
<!-- <Icon Id="viewer_icon" SourceFile="{viewer_icon}"/> -->
<!-- <Icon Id="editor_icon" SourceFile="{editor_icon}"/> -->
<DirectoryRef Id="APPLICATIONFOLDER">
{app_components}
<Component Id="AddToPath" Guid="*">
<Environment Id='UpdatePath' Name='PATH' Action='set' System='yes' Part='last' Value='[APPLICATIONFOLDER]' />
<RegistryValue Root="HKCU" Key="Software\Microsoft\{app}{x64}" Name="system_path_updated" Type="integer" Value="1" KeyPath="yes"/>
</Component>
<Component Id="RememberInstallDir" Guid="*">
<RegistryValue Root="HKLM" Key="Software\{app}{x64}\Installer" Name="InstallPath" Type="string" Value="[APPLICATIONFOLDER]" KeyPath="yes"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="StartMenuShortcuts" Guid="*">
<Shortcut Id="s1" Name="{app}{x64} - E-book management"
Description="Manage your e-book collection and download news"
Target="[#{exe_map[calibre]}]"
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
<Shortcut Id="s2" Name="E-book viewer{x64}"
Description="Viewer for all the major e-book formats"
Target="[#{exe_map[ebook-viewer]}]"
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
<Shortcut Id="s4" Name="Edit E-book{x64}"
Description="Edit e-books"
Target="[#{exe_map[ebook-edit]}]"
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
<Shortcut Id="s3" Name="LRF viewer{x64}"
Description="Viewer for LRF format e-books"
Target="[#{exe_map[lrfviewer]}]"
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
<util:InternetShortcut Id="OnlineDocumentationShortcut"
Name="User Manual" Type="url"
Target="https://manual.calibre-ebook.com"/>
<util:InternetShortcut Id="GetInvolvedS"
Name="Get Involved" Type="url"
Target="https://calibre-ebook.com/get-involved"/>
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\Microsoft\{app}{x64}" Name="start_menu_shortcuts_installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="DesktopFolder">
<Component Id="DesktopShortcut" Guid="*">
<Shortcut Id="ds1" Name="{app}{x64} - E-book management"
Description="Manage your e-book collection and download news"
Target="[#{exe_map[calibre]}]"
WorkingDirectory="APPLICATIONROOTDIRECTORY" />
<RegistryValue Root="HKCU" Key="Software\Microsoft\{app}{x64}" Name="desktop_shortcut_installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
<Feature Id="Complete" Title="{app}" Display="expand" Level="1"
ConfigurableDirectory="APPLICATIONFOLDER">
<Feature Id="MainApplication" Title="Program Files" Level="1"
Description="All the files needed to run {app}" Absent="disallow">
<ComponentRef Id="RememberInstallDir"/>
</Feature>
<Feature Id="FSMS" Title="Start menu shortcuts" Level="1"
Description="Program shortcuts installed in the Start Menu">
<ComponentRef Id="StartMenuShortcuts"/>
</Feature>
<Feature Id="DS" Title="Shortcut on desktop" Level="1"
Description="Shortcut to {app} on your desktop">
<ComponentRef Id="DesktopShortcut"/>
</Feature>
<Feature Id="FAddToPath" Title="Add install directory to path" Level="1"
Description="Add installation directory to PATH. Makes using command line tools easier">
<ComponentRef Id="AddToPath"/>
</Feature>
</Feature>
<!-- Add icon to entry in Add/Remove programs -->
<Property Id="ARPPRODUCTICON" Value="main_icon" />
<Property Id="ARPURLINFOABOUT" Value="https://calibre-ebook.com" />
<Property Id='ARPHELPLINK' Value="https://calibre-ebook.com/help" />
<Property Id='ARPURLUPDATEINFO' Value="https://calibre-ebook.com/download_windows" />
<SetProperty Id="ARPINSTALLLOCATION" Value="[APPLICATIONFOLDER]" After="CostFinalize" />
<Condition
Message="This application is only supported on {minverhuman}, or higher.">
<![CDATA[Installed OR (VersionNT >= {minver})]]>
</Condition>
<!-- On 64 bit installers there is a bug in WiX that causes the
WixSetDefaultPerMachineFolder action to incorrectly set
APPLICATIONFOLDER to the x86 value, so we override it. See
http://stackoverflow.com/questions/5479790/wix-how-to-override-c-program-files-x86-on-x64-machine-in-wixui-advanced-s
-->
<CustomAction
Id="OverwriteWixSetDefaultPerMachineFolder"
Property="WixPerMachineFolder"
Value="[APPLICATIONFOLDER]"
Execute="immediate"
/>
<InstallExecuteSequence>
<Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
{fix_wix}
<RemoveExistingProducts After="InstallFinalize" />
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
{fix_wix}
</InstallUISequence>
<UI>
<UIRef Id="WixUI_Advanced" />
<UIRef Id="WixUI_ErrorProgressText" />
<Publish Dialog="ExitDialog"
Control="Finish"
Event="DoAction"
Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
</UI>
<!--
Set default folder name and allow only per machine installs.
For a per-machine installation, the default installation location
will be [ProgramFilesFolder][ApplicationFolderName] and the user
will be able to change it in the setup UI. This is no longer necessary
(i.e. per user installs should work) but left this way as I
dont want to deal with the complications
-->
<Property Id="ApplicationFolderName" Value="Calibre2" />
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
<Property Id="ALLUSERS" Value="1" />
<WixVariable Id="WixUISupportPerUser" Value="0" />
<!-- Add option to launch calibre after install -->
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch {app}" />
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value="1"/>
<Property Id="WixShellExecTarget" Value="[#{exe_map[calibre]}]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes"/>
</Product>
</Wix>

139
bypy/windows/wix.py Normal file
View File

@ -0,0 +1,139 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import (unicode_literals, division, absolute_import,
print_function)
from itertools import count
import os
import shutil
from bypy.constants import is64bit
from bypy.utils import run
WIXP = r'C:\Program Files (x86)\WiX Toolset v3.11'
if is64bit:
UPGRADE_CODE = '5DD881FF-756B-4097-9D82-8C0F11D521EA'
else:
UPGRADE_CODE = 'BEB2A80D-E902-4DAD-ADF9-8BD2DA42CFE1'
MINVERHUMAN = 'Windows 7'
calibre_constants = globals()['calibre_constants']
CANDLE = WIXP + r'\bin\candle.exe'
LIGHT = WIXP + r'\bin\light.exe'
j, d, a, b = os.path.join, os.path.dirname, os.path.abspath, os.path.basename
def create_installer(env):
if os.path.exists(env.installer_dir):
shutil.rmtree(env.installer_dir)
os.makedirs(env.installer_dir)
with open(j(d(__file__), 'wix-template.xml'), 'rb') as f:
template = f.read().decode('utf-8')
components, smap = get_components_from_files(env)
wxs = template.format(
app=calibre_constants['appname'],
appfolder='Calibre2' if is64bit else 'Calibre',
version=calibre_constants['version'],
upgrade_code=UPGRADE_CODE,
ProgramFilesFolder='ProgramFiles64Folder' if is64bit else 'ProgramFilesFolder',
x64=' 64bit' if is64bit else '',
minverhuman=MINVERHUMAN,
minver='601',
fix_wix='<Custom Action="OverwriteWixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />' if is64bit else '',
compression='high',
app_components=components,
exe_map=smap,
main_icon=j(env.src_root, 'icons', 'library.ico'),
viewer_icon=j(env.src_root, 'icons', 'viewer.ico'),
editor_icon=j(env.src_root, 'icons', 'ebook-edit.ico'),
web_icon=j(env.src_root, 'icons', 'web.ico'),
)
with open(j(d(__file__), 'en-us.xml'), 'rb') as f:
template = f.read().decode('utf-8')
enus = template.format(app=calibre_constants['appname'])
enusf = j(env.installer_dir, 'en-us.wxl')
wxsf = j(env.installer_dir, calibre_constants['appname'] + '.wxs')
with open(wxsf, 'wb') as f:
f.write(wxs.encode('utf-8'))
with open(enusf, 'wb') as f:
f.write(enus.encode('utf-8'))
wixobj = j(env.installer_dir, calibre_constants['appname'] + '.wixobj')
arch = 'x64' if is64bit else 'x86'
cmd = [CANDLE, '-nologo', '-arch', arch, '-ext', 'WiXUtilExtension', '-o', wixobj, wxsf]
run(*cmd)
installer = j(env.dist, '%s%s-%s.msi' % (
calibre_constants['appname'], ('-64bit' if is64bit else ''), calibre_constants['version']))
license = j(env.src_root, 'LICENSE.rtf')
banner = j(env.src_root, 'icons', 'wix-banner.bmp')
dialog = j(env.src_root, 'icons', 'wix-dialog.bmp')
cmd = [LIGHT, '-nologo', '-ext', 'WixUIExtension',
'-cultures:en-us', '-loc', enusf, wixobj,
'-ext', 'WixUtilExtension',
'-o', installer,
'-dWixUILicenseRtf=' + license,
'-dWixUIBannerBmp=' + banner,
'-dWixUIDialogBmp=' + dialog]
cmd.extend([
'-sice:ICE60', # No language in dlls warning
'-sice:ICE61', # Allow upgrading with same version number
'-sice:ICE40', # Re-install mode overriden
'-sice:ICE69', # Shortcut components are part of a different feature than the files they point to
])
cmd.append('-sval') # Disable all checks since they fail when running under ssh
run(*cmd)
def get_components_from_files(env):
file_idc = count()
file_id_map = {}
def process_dir(path):
components = []
for x in os.listdir(path):
f = os.path.join(path, x)
file_id_map[f] = fid = next(file_idc)
if os.path.isdir(f):
components.append(
'<Directory Id="file_%s" FileSource="%s" Name="%s">' %
(file_id_map[f], f, x))
c = process_dir(f)
components.extend(c)
components.append('</Directory>')
else:
checksum = 'Checksum="yes"' if x.endswith('.exe') else ''
c = [
('<Component Id="component_%s" Feature="MainApplication" '
'Guid="*">') % (fid,),
('<File Id="file_%s" Source="%s" Name="%s" ReadOnly="yes" '
'KeyPath="yes" %s/>') %
(fid, f, x, checksum),
'</Component>'
]
if x.endswith('.exe') and not x.startswith('pdf'):
# Add the executable to app paths so that users can
# launch it from the run dialog even if it is not on
# the path. See http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx
c[-1:-1] = [
('<RegistryValue Root="HKLM" '
r'Key="SOFTWARE\Microsoft\Windows\CurrentVersion\App '
r'Paths\%s" Value="[#file_%d]" Type="string" />' % (x, fid)),
('<RegistryValue Root="HKLM" '
r'Key="SOFTWARE\Microsoft\Windows\CurrentVersion\App '
r'Paths\{0}" Name="Path" Value="[APPLICATIONFOLDER]" '
'Type="string" />'.format(x)),
]
components.append('\n'.join(c))
return components
components = process_dir(a(env.base))
smap = {}
for x in calibre_constants['basenames']['gui']:
smap[x] = 'file_%d' % file_id_map[a(j(env.base, x + '.exe'))]
return '\t\t\t\t' + '\n\t\t\t\t'.join(components), smap

View File

@ -61,12 +61,15 @@ content comments
asin The ISBN 10 for the paper book the pages correspond to
pageMap Three value tuple. Looks like: "(N,N,N)"
1) Number of bytes after header that starts the page numbering sequence
2) unknown
3) unknown
1) 1 based page list entry number for the first page described by this tuple.
2) Page number type, a: Indo-Arabic numeral, r: Roman numeral, c: character.
3) Value of page number for the first page of this sequence.
The third value of the tuple is a decimal number if the type is "a" or "r" and
a character string of page labels separated by "|" characters.
Example:
{"asin":"1906694184","pageMap":"(4,a,1)"}
{"asin":"1906694184","pageMap":"(4,a,1),(197,c,A-1|A-2|A-3)"}
Page List
@ -75,3 +78,8 @@ Page List
The page list is a sequence of offsets in the uncompressed HTML. Each
value is the beginning of a new page. Each entry is a 4 byte big endian
int. The list is ordered lowest to highest.
For more information
--------------------
MobileRead wiki https://wiki.mobileread.com/wiki/APNX

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
from __future__ import (unicode_literals, division, absolute_import,
print_function)
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
@ -17,7 +16,7 @@ sources = {'calibre':j(imgsrc, 'calibre.svg'), 'ebook-edit':j(imgsrc, 'tweak.svg
if sys.argv[-1] == 'only-logo':
sources = {'calibre':sources['calibre']}
for name, src in sources.iteritems():
for name, src in sources.items():
iconset = name + '.iconset'
if os.path.exists(iconset):
shutil.rmtree(iconset)
@ -44,4 +43,3 @@ for name, src in sources.iteritems():
subprocess.check_call(['optipng', '-o7', '-strip', 'all', name])
finally:
os.chdir('..')

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
from __future__ import (unicode_literals, division, absolute_import,
print_function)
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL v3'
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
@ -17,7 +16,7 @@ sources = {'library':j(imgsrc, 'calibre.svg'), 'ebook-edit':j(imgsrc, 'tweak.svg
if sys.argv[-1] == 'only-logo':
sources = {'library':sources['library']}
for name, src in sources.iteritems():
for name, src in sources.items():
os.mkdir('ico_temp')
try:
names = []

58
imgsrc/auto-scroll.svg Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1792"
height="1792"
viewBox="0 0 1792 1792"
version="1.1"
id="svg4"
sodipodi:docname="auto-scroll.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1400"
id="namedview6"
showgrid="false"
inkscape:zoom="0.13169643"
inkscape:cx="-1025.0847"
inkscape:cy="896"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="0"
inkscape:current-layer="svg4" />
<path
d="m 1395,864 q 0,13 -10,23 l -466,466 q -10,10 -23,10 -13,0 -23,-10 L 407,887 q -10,-10 -10,-23 0,-13 10,-23 l 50,-50 q 10,-10 23,-10 13,0 23,10 l 393,393 393,-393 q 10,-10 23,-10 13,0 23,10 l 50,50 q 10,10 10,23 z"
id="path823"
style="fill:#2caf45;fill-opacity:1" />
<path
d="m 1395,480 q 0,13 -10,23 L 919,969 q -10,10 -23,10 -13,0 -23,-10 L 407,503 q -10,-10 -10,-23 0,-13 10,-23 l 50,-50 q 10,-10 23,-10 13,0 23,10 l 393,393 393,-393 q 10,-10 23,-10 13,0 23,10 l 50,50 q 10,10 10,23 z"
id="path2"
style="fill:#2271d5;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -15,19 +15,19 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="bookmark.svg">
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="bookmarks.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4139">
<stop
style="stop-color:#6971cf;stop-opacity:1"
style="stop-color:#b2cffa;stop-opacity:1"
offset="0"
id="stop4141" />
<stop
style="stop-color:#1c2057;stop-opacity:0.99215686"
style="stop-color:#0b59bd;stop-opacity:1"
offset="1"
id="stop4143" />
</linearGradient>
@ -50,16 +50,16 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8"
inkscape:cx="-20.56769"
inkscape:cx="49.43231"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="300px"
width="300px"
fill="#eeeeee"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 100 100"
enable-background="new 0 0 100 100"
xml:space="preserve"
id="svg4"
sodipodi:docname="close-for-light-theme.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14"><metadata
id="metadata10"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs8" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1400"
id="namedview6"
showgrid="false"
inkscape:zoom="0.78666667"
inkscape:cx="-171.61017"
inkscape:cy="150"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="0"
inkscape:current-layer="svg4" /><path
d="m 29.082441,32.408474 0.675796,-0.664406 c 2.800483,-2.751801 7.338729,-2.751801 10.139212,0 l 8.831365,8.681779 8.83061,-8.682521 c 2.800483,-2.751801 7.341746,-2.751801 10.139212,0 l 0.675796,0.664407 c 2.800483,2.753284 2.800483,7.216525 0,9.969809 l -8.829856,8.682521 8.83061,8.681038 c 2.800484,2.752543 2.800484,7.215784 0,9.969068 l -0.675796,0.664407 c -2.797466,2.752542 -7.338729,2.752542 -10.139212,0 l -8.831364,-8.681038 -8.830611,8.681038 c -2.800483,2.752542 -7.338728,2.752542 -10.139211,0 l -0.675797,-0.664407 c -2.800483,-2.753284 -2.800483,-7.216525 0,-9.969068 l 8.829856,-8.681038 -8.83061,-8.681779 c -2.800483,-2.753284 -2.800483,-7.216526 0,-9.96981 z m 19.646373,55.727119 c -20.827509,0 -37.711865,-16.599788 -37.711865,-37.07553 0,-20.476483 16.884356,-37.077012 37.711865,-37.077012 20.827508,0 37.711864,16.600529 37.711864,37.077012 0,20.475742 -16.884356,37.07553 -37.711864,37.07553 z"
id="path2"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill-rule:evenodd;stroke-width:0.74785435" /></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="300px"
width="300px"
fill="#000000"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 100 100"
enable-background="new 0 0 100 100"
xml:space="preserve"
id="svg4"
sodipodi:docname="close-for-light-theme.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14"><metadata
id="metadata10"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs8" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1400"
id="namedview6"
showgrid="false"
inkscape:zoom="0.78666667"
inkscape:cx="-171.61017"
inkscape:cy="150"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="0"
inkscape:current-layer="svg4" /><path
d="m 29.082441,32.408474 0.675796,-0.664406 c 2.800483,-2.751801 7.338729,-2.751801 10.139212,0 l 8.831365,8.681779 8.83061,-8.682521 c 2.800483,-2.751801 7.341746,-2.751801 10.139212,0 l 0.675796,0.664407 c 2.800483,2.753284 2.800483,7.216525 0,9.969809 l -8.829856,8.682521 8.83061,8.681038 c 2.800484,2.752543 2.800484,7.215784 0,9.969068 l -0.675796,0.664407 c -2.797466,2.752542 -7.338729,2.752542 -10.139212,0 l -8.831364,-8.681038 -8.830611,8.681038 c -2.800483,2.752542 -7.338728,2.752542 -10.139211,0 l -0.675797,-0.664407 c -2.800483,-2.753284 -2.800483,-7.216525 0,-9.969068 l 8.829856,-8.681038 -8.83061,-8.681779 c -2.800483,-2.753284 -2.800483,-7.216526 0,-9.96981 z m 19.646373,55.727119 c -20.827509,0 -37.711865,-16.599788 -37.711865,-37.07553 0,-20.476483 16.884356,-37.077012 37.711865,-37.077012 20.827508,0 37.711864,16.600529 37.711864,37.077012 0,20.475742 -16.884356,37.07553 -37.711864,37.07553 z"
id="path2"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill-rule:evenodd;stroke-width:0.74785435" /></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="code.svg">
<defs
id="defs4" />
@ -25,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:zoom="5.6568542"
inkscape:cx="19.843024"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -89,6 +89,7 @@
<path
inkscape:connector-curvature="0"
d="m 41.265039,1017.4603 -3.314134,3.3141 q -0.662836,0.6629 -1.524529,0.6629 -0.861692,0 -1.524481,-0.6629 L 4.0141368,989.88668 Q 3.3513,989.22388 3.3513,988.3622 q 0,-0.86167 0.6628368,-1.52454 L 34.901895,955.94989 q 0.662789,-0.66273 1.524481,-0.66273 0.861693,0 1.524529,0.66273 l 3.314134,3.31417 q 0.662789,0.66281 0.662789,1.52455 0,0.86167 -0.662789,1.52448 l -26.049143,26.04911 26.049143,26.0491 q 0.662789,0.6628 0.662789,1.5245 0,0.8616 -0.662789,1.5245 z m 39.173095,-70.72369 -24.723471,85.57099 q -0.265123,0.8617 -1.02741,1.2926 -0.76224,0.4307 -1.557621,0.1656 l -4.109552,-1.1268 q -0.861648,-0.2651 -1.292492,-1.0273 -0.430844,-0.7623 -0.165722,-1.624 l 24.723471,-85.57098 q 0.265123,-0.86167 1.027363,-1.29251 0.762287,-0.43084 1.557668,-0.1657 l 4.109505,1.12681 q 0.861695,0.26514 1.292539,1.02738 0.430844,0.7623 0.165722,1.62391 z m 43.547726,43.15007 -30.887755,30.88772 q -0.66284,0.6629 -1.524481,0.6629 -0.861695,0 -1.524528,-0.6629 l -3.314137,-3.3141 q -0.662833,-0.6629 -0.662833,-1.5245 0,-0.8617 0.662833,-1.5245 L 112.78411,988.3622 86.734959,962.31309 q -0.662833,-0.66281 -0.662833,-1.52448 0,-0.86174 0.662833,-1.52455 l 3.314137,-3.31417 q 0.662833,-0.66273 1.524528,-0.66273 0.861641,0 1.524481,0.66273 l 30.887755,30.88777 q 0.66284,0.66287 0.66284,1.52454 0,0.86168 -0.66284,1.52448 z"
id="path4" />
id="path4"
style="fill:#2271d5;fill-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -5,7 +5,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0"
@ -16,7 +15,7 @@
enable-background="new 0 0 76.11 100"
xml:space="preserve"
id="svg2"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="compress-image.svg"
width="256"
height="256"
@ -24,23 +23,7 @@
id="metadata16"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs14"><linearGradient
inkscape:collect="always"
id="linearGradient4136"><stop
style="stop-color:#0d57c1;stop-opacity:1"
offset="0"
id="stop4138" /><stop
style="stop-color:#031125;stop-opacity:1"
offset="1"
id="stop4140" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4136"
id="linearGradient4142"
x1="3.9792354"
y1="253.00003"
x2="252.39026"
y2="6.1779814"
gradientUnits="userSpaceOnUse" /></defs><sodipodi:namedview
id="defs14" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
@ -49,29 +32,29 @@
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
id="namedview12"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.888"
inkscape:cx="-467.2416"
inkscape:cy="37.499"
inkscape:zoom="2.6700352"
inkscape:cx="22.265054"
inkscape:cy="127.38546"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" /><path
d="m 222.1275,226.88826 c -3.9632,0 -7.44761,1.92415 -9.44305,4.82059 l -28.9242,0 0,-11.26929 c 0,-0.82683 -0.71958,-1.49543 -1.59414,-1.49543 l -2.40782,0 0,-6.35429 8.80374,0 c 1.31185,0 2.40505,-0.99269 2.40505,-2.21762 l 0,-27.53524 c 0,-1.23002 -1.09597,-2.23803 -2.40505,-2.23803 l -8.80374,0 0,-4.85886 2.89492,0 2.41888,-8.18402 3.48718,0 c 1.31184,0 2.40781,-1.0029 2.40781,-2.23293 l 0,-6.86212 c 0,-1.21727 -1.09597,-2.22272 -2.40781,-2.22272 l -38.53332,0 c -1.32844,0 -2.39674,1.00801 -2.39674,2.22272 l 0,6.86212 c 0,1.23003 1.0683,2.23293 2.39674,2.23293 l 3.48441,0 2.40505,8.18402 3.0499,0 0,4.85886 -63.950964,0 c -3.965973,0 -7.192996,-2.99596 -7.192996,-6.65797 l 0,-123.484967 c 0,-3.672216 3.229791,-6.675829 7.192996,-6.675829 l 52.612094,0 0,5.126812 c 0,1.217267 1.0683,2.21762 2.39675,2.21762 l 38.53331,0 c 1.31184,0 2.40781,-1.002905 2.40781,-2.21762 l 0,-6.864671 c 0,-1.227475 -1.09597,-2.220172 -2.40781,-2.220172 l -4.58038,0 C 144.32193,3.4138771 87.923751,0.48937416 87.923751,0.48937416 86.833316,0.43323187 85.737346,0.40516072 84.644144,0.40516072 50.41722,0.40516072 22.677553,26.138745 22.677553,57.892314 l 0,113.004226 c 0,31.74336 27.739667,51.62539 61.966591,51.62539 1.093202,0 2.189172,-0.0255 3.279607,-0.0689 0,0 28.796889,-1.48521 59.702689,-15.62542 l 0,3.54462 c 0,1.22493 1.0683,2.21762 2.39675,2.21762 l 8.93658,0 0,6.35429 -2.54619,0 c -0.88563,0 -1.59414,0.6686 -1.59414,1.49543 l 0,11.26929 -29.05151,0 c -1.99544,-2.89644 -5.48262,-4.82059 -9.44582,-4.82059 -6.18836,0 -11.19495,4.65981 -11.19495,10.38633 0,5.72651 5.00659,10.37611 11.19495,10.37611 3.9632,0 7.44761,-1.92414 9.44582,-4.82568 l 29.05705,0 0,11.2795 c 0,0.83192 0.7085,1.49032 1.59413,1.49032 l 25.74976,0 c 0.8718,0 1.59414,-0.6584 1.59414,-1.49032 l 0,-11.2795 28.9242,0 c 1.99544,2.90154 5.47985,4.82568 9.44306,4.82568 6.18835,0 11.19218,-4.6496 11.19218,-10.37611 0,-5.72652 -5.00383,-10.38633 -11.19495,-10.38633 z"
id="path4"
inkscape:connector-curvature="0"
style="fill:url(#linearGradient4142);fill-opacity:1" /><path
style="fill:#2caf45;fill-opacity:1" /><path
d="m 223.19745,54.706661 -123.986485,0 c -4.890824,0 -8.856178,3.643725 -8.856178,8.137856 l 0,81.378573 c 0,4.49413 3.965354,8.13785 8.856178,8.13785 l 123.986485,0 c 4.89083,0 8.85618,-3.64372 8.85618,-8.13785 l 0,-81.378573 c 0,-4.494131 -3.96535,-8.137856 -8.85618,-8.137856 z m 0,89.516429 -123.986485,0 0,-81.378573 123.986485,0 0,81.378573 z"
id="path7"
inkscape:connector-curvature="0"
style="fill:#546e7a" /><path
style="fill:#2271d5;fill-opacity:1" /><path
d="m 125.7795,79.120231 c 4.89525,0 8.85617,3.639656 8.85617,8.137857 0,4.4982 -3.96092,8.137857 -8.85617,8.137857 -4.89525,0 -8.85618,-3.639657 -8.85618,-8.137857 0,-4.498201 3.96093,-8.137857 8.85618,-8.137857 m 0,-8.137857 c -9.76837,0 -17.71236,7.299658 -17.71236,16.275714 0,8.976056 7.94399,16.275712 17.71236,16.275712 9.76836,0 17.71235,-7.299656 17.71235,-16.275712 0,-8.976056 -7.94399,-16.275714 -17.71235,-16.275714 l 0,0 z"
id="path9"
inkscape:connector-curvature="0"

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="connect_share.svg">
<defs
id="defs4">
@ -23,7 +23,7 @@
inkscape:collect="always"
id="linearGradient4151">
<stop
style="stop-color:#3d70e4;stop-opacity:1"
style="stop-color:#5280e7;stop-opacity:1"
offset="0"
id="stop4153" />
<stop
@ -31,7 +31,7 @@
offset="0.53151304"
style="stop-color:#123380;stop-opacity:1" />
<stop
style="stop-color:#161c1c;stop-opacity:1"
style="stop-color:#405151;stop-opacity:1"
offset="0.53151304"
id="stop4161" />
<stop
@ -63,10 +63,10 @@
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="debug.svg">
<defs
id="defs4">
@ -50,17 +50,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="41.906986"
inkscape:cy="69.707741"
inkscape:cy="63.245904"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -111,36 +111,49 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36216)">
<path
d="m 27.985299,942.40335 c 0.58138,0 1.167905,-0.12742 1.720988,-0.39475 l 16.013679,-7.75514 1.880482,4.44472 c 2.1686,-1.32667 4.506983,-2.41599 6.991997,-3.19051 l -3.313352,-7.83009 c -0.01801,-0.0425 -0.04631,-0.0749 -0.06431,-0.11992 -0.02058,-0.0425 -0.03087,-0.0874 -0.05145,-0.12742 -0.03859,-0.075 -0.09004,-0.13742 -0.133769,-0.20487 -0.06688,-0.11243 -0.133769,-0.22237 -0.208371,-0.3248 -0.07717,-0.0999 -0.159493,-0.19238 -0.246958,-0.28482 -0.07975,-0.0899 -0.162066,-0.17739 -0.254675,-0.25984 -0.09775,-0.0874 -0.198081,-0.1649 -0.303552,-0.23985 -0.09261,-0.0675 -0.185219,-0.13741 -0.282973,-0.19488 -0.113189,-0.0675 -0.231523,-0.12742 -0.349857,-0.17988 -0.105472,-0.05 -0.205798,-0.0974 -0.31127,-0.13742 -0.126052,-0.045 -0.252103,-0.0774 -0.375582,-0.11243 -0.113189,-0.03 -0.223806,-0.055 -0.336995,-0.0725 -0.131196,-0.025 -0.25982,-0.035 -0.391016,-0.045 -0.115762,-0.005 -0.231523,-0.015 -0.35243,-0.01 -0.131196,0.003 -0.262393,0.0175 -0.391017,0.035 -0.120906,0.015 -0.241813,0.03 -0.362719,0.055 -0.128624,0.0275 -0.257248,0.0699 -0.380727,0.10993 -0.07975,0.0275 -0.159494,0.04 -0.236668,0.0675 -0.04631,0.02 -0.07975,0.0475 -0.126051,0.0625 -0.04116,0.02 -0.08746,0.03 -0.131197,0.05 L 26.26174,935.2979 c -1.906206,0.92192 -2.683095,3.17301 -1.731278,5.02685 0.676562,1.31917 2.037403,2.07869 3.454839,2.07869 z"
id="path4160" />
<path
d="m 49.082196,942.20598 c -1.77501,1.14928 -3.398244,2.50093 -4.849122,4.00998 -0.07717,0.0824 -0.156921,0.1674 -0.234096,0.25235 -0.640547,0.68707 -1.247652,1.40911 -1.811025,2.15864 -0.06174,0.0824 -0.131196,0.1624 -0.190363,0.24735 -1.216783,1.65896 -2.238056,3.46033 -3.035525,5.36664 -0.06946,0.16989 -0.128624,0.34728 -0.195508,0.51467 -0.29069,0.74953 -0.550511,1.51405 -0.774316,2.29606 -0.07975,0.28233 -0.156921,0.57215 -0.228951,0.86446 -0.177501,0.71206 -0.318987,1.4391 -0.434749,2.17614 -0.0463,0.29231 -0.100326,0.57963 -0.138914,0.87945 -0.123479,1.00936 -0.203225,2.03372 -0.203225,3.07807 l 0,0.005 c 0,2.01624 0.275255,4.00749 0.753736,5.95877 0.262393,-0.25484 0.55051,-0.46971 0.818048,-0.71205 0.691997,-0.62961 1.381421,-1.25921 2.104287,-1.83136 0.501634,-0.40224 1.031564,-0.75702 1.551205,-1.12929 0.545366,-0.39475 1.085586,-0.7995 1.646386,-1.16427 0.553083,-0.35977 1.126746,-0.67957 1.692691,-1.01186 0.558228,-0.3248 1.113883,-0.6496 1.682401,-0.94441 0.58138,-0.29981 1.170478,-0.57214 1.767293,-0.84197 0.59167,-0.26734 1.188485,-0.52717 1.790445,-0.76702 0.589098,-0.22986 1.18334,-0.44722 1.782728,-0.6496 0.653409,-0.21986 1.311964,-0.40974 1.978236,-0.58963 0.57109,-0.1549 1.137035,-0.3123 1.715843,-0.44222 0.779461,-0.17239 1.564067,-0.29731 2.353818,-0.41724 0.483626,-0.0725 0.962107,-0.16989 1.448305,-0.22486 1.291384,-0.14241 2.587914,-0.22736 3.897305,-0.22985 0.0077,0 0.01801,0 0.02315,0 0.0026,0 0.0026,0 0.0026,0 0.0026,0 0.0026,0 0.0026,0 1.322254,0 2.626501,0.0874 3.928171,0.23235 0.47076,0.0525 0.92867,0.14491 1.39686,0.21237 0.80776,0.12242 1.61809,0.25484 2.41555,0.42973 0.5608,0.12742 1.11132,0.27732 1.66183,0.42973 0.68427,0.18488 1.36341,0.38476 2.0374,0.60962 0.58652,0.19487 1.16019,0.40724 1.73385,0.6321 0.61997,0.24485 1.23222,0.50968 1.84447,0.78451 0.58138,0.26483 1.15761,0.52967 1.72613,0.82198 0.58395,0.30231 1.1499,0.63461 1.72099,0.9669 0.55823,0.32729 1.1216,0.64459 1.66439,0.99437 0.56595,0.36977 1.11388,0.77952 1.66182,1.17677 0.51193,0.37226 1.03671,0.72454 1.53577,1.12179 0.69972,0.55716 1.37113,1.16677 2.04512,1.77639 0.28812,0.26234 0.59939,0.49719 0.88494,0.77202 0.4759,-1.95128 0.75116,-3.94753 0.75116,-5.96377 0,-1.03934 -0.0798,-2.05871 -0.20065,-3.07057 -0.0515,-0.40974 -0.13635,-0.8045 -0.20323,-1.20924 -0.0978,-0.57214 -0.20323,-1.14429 -0.33957,-1.70394 -0.0952,-0.40474 -0.20322,-0.80199 -0.31898,-1.19675 -0.18265,-0.6271 -0.39359,-1.24172 -0.62254,-1.84634 -0.10548,-0.27982 -0.19551,-0.56464 -0.31127,-0.83697 -0.36787,-0.87446 -0.77947,-1.72142 -1.23479,-2.54591 -0.1029,-0.18738 -0.22124,-0.36727 -0.33185,-0.55215 -0.40646,-0.68957 -0.83863,-1.36415 -1.3094,-2.01374 -0.12347,-0.17489 -0.24953,-0.34728 -0.37558,-0.51718 -1.22192,-1.61398 -2.61878,-3.09056 -4.1777,-4.39474 -0.054,-0.0475 -0.11319,-0.09 -0.16979,-0.13742 -0.74601,-0.61211 -1.53062,-1.18925 -2.34352,-1.71892 -2.21491,-1.45409 -4.65362,-2.60587 -7.26726,-3.37288 -0.33956,-0.0974 -0.68685,-0.17989 -1.02641,-0.26484 -0.40131,-0.0999 -0.80262,-0.19738 -1.21164,-0.27982 -0.32156,-0.065 -0.64827,-0.12742 -0.97497,-0.17989 -0.47591,-0.0774 -0.95439,-0.14491 -1.44059,-0.19988 -0.27011,-0.03 -0.54279,-0.065 -0.81805,-0.0874 -0.769167,-0.0625 -1.543483,-0.10743 -2.328089,-0.10743 l -0.0051,0 c -0.825766,0 -1.643814,0.05 -2.451572,0.12242 -0.27011,0.0225 -0.537648,0.055 -0.805186,0.0874 -0.542793,0.0625 -1.080441,0.1474 -1.612944,0.23984 -0.298407,0.0525 -0.594242,0.10244 -0.890077,0.1649 -0.609678,0.12742 -1.21421,0.28232 -1.80588,0.44972 -0.120907,0.035 -0.246958,0.0575 -0.367865,0.0974 l 0,-0.005 c -2.505594,0.74703 -4.849122,1.83885 -6.984279,3.21799 l 0.0051,0.0125 z"
id="path4158" />
<path
d="m 82.28518,934.25596 16.01368,7.75514 c 0.55308,0.26733 1.139601,0.39475 1.71841,0.39475 1.41744,0 2.78085,-0.76202 3.45741,-2.0737 0.94925,-1.85384 0.17493,-4.10493 -1.73385,-5.02685 l -19.72576,-9.55401 c -0.0437,-0.02 -0.0849,-0.0275 -0.12863,-0.0475 -0.0437,-0.0175 -0.0797,-0.0475 -0.12605,-0.065 -0.0772,-0.03 -0.15949,-0.0425 -0.23924,-0.0675 -0.12862,-0.0425 -0.25467,-0.0824 -0.38073,-0.10993 -0.1209,-0.0275 -0.23924,-0.0425 -0.36014,-0.055 -0.1312,-0.015 -0.2624,-0.03 -0.39102,-0.035 -0.12091,-0.003 -0.23924,0.005 -0.36015,0.0125 -0.12862,0.007 -0.25467,0.02 -0.38072,0.0425 -0.11834,0.02 -0.2341,0.05 -0.34986,0.0774 -0.12348,0.0325 -0.24181,0.0625 -0.36272,0.10744 -0.11319,0.045 -0.22123,0.0924 -0.32928,0.14491 -0.11319,0.0525 -0.2238,0.10743 -0.33185,0.16989 -0.10547,0.06 -0.20322,0.13492 -0.30098,0.20487 -0.10032,0.0725 -0.19551,0.14741 -0.28812,0.22986 -0.0952,0.0824 -0.1775,0.17239 -0.26496,0.26483 -0.0823,0.0924 -0.16207,0.17989 -0.23924,0.27733 -0.0746,0.10243 -0.14406,0.21486 -0.21094,0.32729 -0.0437,0.0675 -0.0952,0.13242 -0.13377,0.20487 -0.0232,0.04 -0.0309,0.085 -0.0514,0.12742 -0.0206,0.045 -0.0489,0.0775 -0.0643,0.11993 l -3.32107,7.84508 c 2.48501,0.77702 4.84397,1.82636 7.01257,3.15552 l 1.87277,-4.42722 z"
id="path4156" />
<path
d="m 25.639199,989.21152 c 0.848918,-2.44597 1.877909,-4.76701 3.045814,-6.99312 -6.554675,-1.81636 -12.576847,-6.09118 -16.890894,-9.55401 -1.646386,-1.31917 -4.0773782,-1.09431 -5.4330752,0.49719 -1.358268,1.5965 -1.126745,3.95752 0.514496,5.27419 4.7153532,3.79263 11.2443042,8.4622 18.7636592,10.77575 z"
id="path4154" />
<path
d="m 102.35823,989.21652 c 7.52192,-2.31355 14.05345,-6.98812 18.77137,-10.77825 1.64382,-1.31667 1.87277,-3.68269 0.51193,-5.27419 -1.35313,-1.5965 -3.79184,-1.81886 -5.43051,-0.49719 -4.31919,3.47032 -10.34136,7.74514 -16.896039,9.55901 1.165339,2.2236 2.194329,4.54965 3.043249,6.99062 z"
id="path4152" />
<path
d="m 102.35823,1025.0616 c -0.84635,2.441 -1.87534,4.767 -3.045819,6.9931 6.557249,1.8114 12.581989,6.0862 16.896039,9.554 0.71772,0.5796 1.58979,0.8595 2.45672,0.8595 1.11131,0 2.21233,-0.4647 2.97636,-1.3567 1.35569,-1.5965 1.12674,-3.9575 -0.5145,-5.2791 -4.71793,-3.7877 -11.24688,-8.4622 -18.7688,-10.7708 z"
id="path4150" />
<path
d="m 123.14128,1003.3876 -17.93532,0 c 0.0823,1.2442 0.16207,2.4884 0.16207,3.7526 0,1.2642 -0.0797,2.5035 -0.16207,3.7427 l 17.93532,0 c 2.13001,0 3.85872,-1.679 3.85872,-3.7477 0,-2.0687 -1.72871,-3.7476 -3.85872,-3.7476 z"
id="path4148" />
<path
d="m 90.66117,975.97232 c -0.09,-0.10744 -0.1775,-0.21487 -0.27011,-0.3223 -0.76917,-0.90194 -1.56922,-1.7614 -2.4027,-2.58088 -0.10547,-0.10244 -0.21094,-0.20238 -0.31641,-0.30231 -0.84892,-0.81949 -1.72356,-1.599 -2.63165,-2.32855 -0.072,-0.0575 -0.15178,-0.11243 -0.2238,-0.16989 -1.88563,-1.49406 -3.89474,-2.78076 -5.99902,-3.85258 -0.11319,-0.055 -0.22381,-0.11993 -0.337,-0.1749 -0.99812,-0.49469 -2.01939,-0.92941 -3.05868,-1.32417 -0.16463,-0.06 -0.32927,-0.12492 -0.49391,-0.18238 -1.02642,-0.36727 -2.07599,-0.68957 -3.141,-0.9544 -0.17235,-0.045 -0.34986,-0.0824 -0.52478,-0.12243 -1.08302,-0.25484 -2.18147,-0.45971 -3.29535,-0.59462 -0.13377,-0.0175 -0.26754,-0.025 -0.40131,-0.04 -1.17305,-0.13242 -2.361531,-0.21486 -3.568023,-0.21486 -1.250225,0 -2.487587,0.0774 -3.706942,0.21986 -0.509351,0.06 -1.005839,0.17489 -1.512617,0.25984 -0.689425,0.11492 -1.381421,0.21486 -2.060556,0.36976 -0.658554,0.15491 -1.296529,0.36228 -1.939649,0.55715 -0.496488,0.14991 -1.000694,0.27983 -1.486892,0.45472 -0.738302,0.25984 -1.461168,0.57214 -2.181462,0.88445 -0.36272,0.1549 -0.728012,0.30231 -1.088159,0.4697 -0.792323,0.37726 -1.558922,0.7995 -2.322948,1.23673 -0.25982,0.1524 -0.522213,0.28732 -0.779461,0.44472 -0.812903,0.49469 -1.605226,1.02935 -2.382115,1.5915 -0.185218,0.13242 -0.373009,0.25984 -0.553083,0.39475 -0.807758,0.60962 -1.594936,1.25422 -2.361535,1.9263 -0.133769,0.11992 -0.267538,0.23735 -0.401307,0.35727 -0.776888,0.70706 -1.530624,1.44659 -2.256063,2.22111 -0.105472,0.11243 -0.210944,0.22236 -0.313843,0.33729 -0.87207,0.94441 -1.700408,1.94128 -2.497876,2.97813 -0.295835,0.38726 -0.609678,0.76202 -0.895223,1.16427 -0.86178,1.19675 -1.659249,2.45596 -2.410412,3.76015 -4.018212,7.06057 -6.366885,15.56024 -6.366885,24.70945 0,12.21 4.180278,23.263 10.938179,31.2805 0.04116,0.05 0.08232,0.097 0.126051,0.1474 1.59751,1.8738 3.34165,3.5778 5.201552,5.0893 0.172356,0.1424 0.349857,0.2823 0.524786,0.4198 0.884932,0.697 1.787872,1.3516 2.724255,1.9562 0.149203,0.097 0.30098,0.1799 0.450183,0.2724 0.823193,0.5171 1.669539,0.9943 2.528747,1.4391 0.221233,0.1174 0.442466,0.2398 0.668844,0.3472 0.959535,0.4723 1.939649,0.897 2.940343,1.2742 0.236668,0.087 0.478481,0.1649 0.717722,0.2499 0.900367,0.3173 1.813597,0.5996 2.742262,0.8345 0.180073,0.05 0.357574,0.1024 0.537648,0.1474 1.057289,0.2498 2.132585,0.4397 3.220743,0.5796 0.262393,0.035 0.522213,0.062 0.784606,0.092 0.486198,0.05 0.990404,0.052 1.481748,0.087 l 0,-61.07677 c 0,-1.03436 0.864352,-1.87383 1.929359,-1.87383 1.065006,0 1.929363,0.83947 1.929363,1.87383 l 0,61.06927 c 0.49648,-0.04 1.00326,-0.04 1.49461,-0.092 0.24953,-0.025 0.49906,-0.053 0.74859,-0.082 1.10359,-0.1474 2.19432,-0.3373 3.26704,-0.5896 0.14664,-0.035 0.28812,-0.077 0.43218,-0.1174 0.98012,-0.2499 1.94222,-0.5422 2.89147,-0.8795 0.20065,-0.072 0.40645,-0.1374 0.6071,-0.2149 1.02899,-0.3847 2.04255,-0.8244 3.03295,-1.3066 0.17751,-0.088 0.35243,-0.1849 0.52736,-0.2724 0.93381,-0.4822 1.85476,-0.9993 2.74484,-1.5665 0.09,-0.053 0.18264,-0.1074 0.27268,-0.1649 0.97754,-0.6296 1.92421,-1.3117 2.84259,-2.0387 0.12605,-0.097 0.24953,-0.1999 0.37301,-0.2973 9.86545,-7.9875 16.34553,-21.3916 16.34553,-36.5897 0.005,-12.15982 -4.13912,-23.16292 -10.84557,-31.1704 z"
id="path4146"
style="fill:url(#radialGradient4168);fill-opacity:1" />
<path
d="m 22.624254,1007.1402 c 0,-1.2642 0.07975,-2.5084 0.164638,-3.7526 l -17.9301752,0 c -2.130012,0 -3.858718,1.6789 -3.858718,3.7476 0,2.0687 1.728706,3.7477 3.858718,3.7477 l 17.9327482,0 c -0.08746,-1.2392 -0.167211,-2.481 -0.167211,-3.7427 z"
id="path4144" />
<path
d="m 6.8729678,1035.8324 c -1.643814,1.3216 -1.875337,3.6851 -0.514496,5.2791 0.761454,0.892 1.867619,1.3567 2.9763584,1.3567 0.8643518,0 1.7364228,-0.2823 2.4567168,-0.8595 4.316619,-3.4703 10.336218,-7.7401 16.890894,-9.554 -1.167905,-2.2261 -2.196897,-4.5521 -3.045815,-6.9931 -7.516782,2.3136 -14.048305,6.9831 -18.7636582,10.7708 z"
id="path4" />
<g
id="g835"
style="fill:#dd8808;fill-opacity:1">
<path
id="path4160"
d="m 27.985299,942.40335 c 0.58138,0 1.167905,-0.12742 1.720988,-0.39475 l 16.013679,-7.75514 1.880482,4.44472 c 2.1686,-1.32667 4.506983,-2.41599 6.991997,-3.19051 l -3.313352,-7.83009 c -0.01801,-0.0425 -0.04631,-0.0749 -0.06431,-0.11992 -0.02058,-0.0425 -0.03087,-0.0874 -0.05145,-0.12742 -0.03859,-0.075 -0.09004,-0.13742 -0.133769,-0.20487 -0.06688,-0.11243 -0.133769,-0.22237 -0.208371,-0.3248 -0.07717,-0.0999 -0.159493,-0.19238 -0.246958,-0.28482 -0.07975,-0.0899 -0.162066,-0.17739 -0.254675,-0.25984 -0.09775,-0.0874 -0.198081,-0.1649 -0.303552,-0.23985 -0.09261,-0.0675 -0.185219,-0.13741 -0.282973,-0.19488 -0.113189,-0.0675 -0.231523,-0.12742 -0.349857,-0.17988 -0.105472,-0.05 -0.205798,-0.0974 -0.31127,-0.13742 -0.126052,-0.045 -0.252103,-0.0774 -0.375582,-0.11243 -0.113189,-0.03 -0.223806,-0.055 -0.336995,-0.0725 -0.131196,-0.025 -0.25982,-0.035 -0.391016,-0.045 -0.115762,-0.005 -0.231523,-0.015 -0.35243,-0.01 -0.131196,0.003 -0.262393,0.0175 -0.391017,0.035 -0.120906,0.015 -0.241813,0.03 -0.362719,0.055 -0.128624,0.0275 -0.257248,0.0699 -0.380727,0.10993 -0.07975,0.0275 -0.159494,0.04 -0.236668,0.0675 -0.04631,0.02 -0.07975,0.0475 -0.126051,0.0625 -0.04116,0.02 -0.08746,0.03 -0.131197,0.05 L 26.26174,935.2979 c -1.906206,0.92192 -2.683095,3.17301 -1.731278,5.02685 0.676562,1.31917 2.037403,2.07869 3.454839,2.07869 z"
style="fill:#dd8808;fill-opacity:1" />
<path
id="path4158"
d="m 49.082196,942.20598 c -1.77501,1.14928 -3.398244,2.50093 -4.849122,4.00998 -0.07717,0.0824 -0.156921,0.1674 -0.234096,0.25235 -0.640547,0.68707 -1.247652,1.40911 -1.811025,2.15864 -0.06174,0.0824 -0.131196,0.1624 -0.190363,0.24735 -1.216783,1.65896 -2.238056,3.46033 -3.035525,5.36664 -0.06946,0.16989 -0.128624,0.34728 -0.195508,0.51467 -0.29069,0.74953 -0.550511,1.51405 -0.774316,2.29606 -0.07975,0.28233 -0.156921,0.57215 -0.228951,0.86446 -0.177501,0.71206 -0.318987,1.4391 -0.434749,2.17614 -0.0463,0.29231 -0.100326,0.57963 -0.138914,0.87945 -0.123479,1.00936 -0.203225,2.03372 -0.203225,3.07807 l 0,0.005 c 0,2.01624 0.275255,4.00749 0.753736,5.95877 0.262393,-0.25484 0.55051,-0.46971 0.818048,-0.71205 0.691997,-0.62961 1.381421,-1.25921 2.104287,-1.83136 0.501634,-0.40224 1.031564,-0.75702 1.551205,-1.12929 0.545366,-0.39475 1.085586,-0.7995 1.646386,-1.16427 0.553083,-0.35977 1.126746,-0.67957 1.692691,-1.01186 0.558228,-0.3248 1.113883,-0.6496 1.682401,-0.94441 0.58138,-0.29981 1.170478,-0.57214 1.767293,-0.84197 0.59167,-0.26734 1.188485,-0.52717 1.790445,-0.76702 0.589098,-0.22986 1.18334,-0.44722 1.782728,-0.6496 0.653409,-0.21986 1.311964,-0.40974 1.978236,-0.58963 0.57109,-0.1549 1.137035,-0.3123 1.715843,-0.44222 0.779461,-0.17239 1.564067,-0.29731 2.353818,-0.41724 0.483626,-0.0725 0.962107,-0.16989 1.448305,-0.22486 1.291384,-0.14241 2.587914,-0.22736 3.897305,-0.22985 0.0077,0 0.01801,0 0.02315,0 0.0026,0 0.0026,0 0.0026,0 0.0026,0 0.0026,0 0.0026,0 1.322254,0 2.626501,0.0874 3.928171,0.23235 0.47076,0.0525 0.92867,0.14491 1.39686,0.21237 0.80776,0.12242 1.61809,0.25484 2.41555,0.42973 0.5608,0.12742 1.11132,0.27732 1.66183,0.42973 0.68427,0.18488 1.36341,0.38476 2.0374,0.60962 0.58652,0.19487 1.16019,0.40724 1.73385,0.6321 0.61997,0.24485 1.23222,0.50968 1.84447,0.78451 0.58138,0.26483 1.15761,0.52967 1.72613,0.82198 0.58395,0.30231 1.1499,0.63461 1.72099,0.9669 0.55823,0.32729 1.1216,0.64459 1.66439,0.99437 0.56595,0.36977 1.11388,0.77952 1.66182,1.17677 0.51193,0.37226 1.03671,0.72454 1.53577,1.12179 0.69972,0.55716 1.37113,1.16677 2.04512,1.77639 0.28812,0.26234 0.59939,0.49719 0.88494,0.77202 0.4759,-1.95128 0.75116,-3.94753 0.75116,-5.96377 0,-1.03934 -0.0798,-2.05871 -0.20065,-3.07057 -0.0515,-0.40974 -0.13635,-0.8045 -0.20323,-1.20924 -0.0978,-0.57214 -0.20323,-1.14429 -0.33957,-1.70394 -0.0952,-0.40474 -0.20322,-0.80199 -0.31898,-1.19675 -0.18265,-0.6271 -0.39359,-1.24172 -0.62254,-1.84634 -0.10548,-0.27982 -0.19551,-0.56464 -0.31127,-0.83697 -0.36787,-0.87446 -0.77947,-1.72142 -1.23479,-2.54591 -0.1029,-0.18738 -0.22124,-0.36727 -0.33185,-0.55215 -0.40646,-0.68957 -0.83863,-1.36415 -1.3094,-2.01374 -0.12347,-0.17489 -0.24953,-0.34728 -0.37558,-0.51718 -1.22192,-1.61398 -2.61878,-3.09056 -4.1777,-4.39474 -0.054,-0.0475 -0.11319,-0.09 -0.16979,-0.13742 -0.74601,-0.61211 -1.53062,-1.18925 -2.34352,-1.71892 -2.21491,-1.45409 -4.65362,-2.60587 -7.26726,-3.37288 -0.33956,-0.0974 -0.68685,-0.17989 -1.02641,-0.26484 -0.40131,-0.0999 -0.80262,-0.19738 -1.21164,-0.27982 -0.32156,-0.065 -0.64827,-0.12742 -0.97497,-0.17989 -0.47591,-0.0774 -0.95439,-0.14491 -1.44059,-0.19988 -0.27011,-0.03 -0.54279,-0.065 -0.81805,-0.0874 -0.769167,-0.0625 -1.543483,-0.10743 -2.328089,-0.10743 l -0.0051,0 c -0.825766,0 -1.643814,0.05 -2.451572,0.12242 -0.27011,0.0225 -0.537648,0.055 -0.805186,0.0874 -0.542793,0.0625 -1.080441,0.1474 -1.612944,0.23984 -0.298407,0.0525 -0.594242,0.10244 -0.890077,0.1649 -0.609678,0.12742 -1.21421,0.28232 -1.80588,0.44972 -0.120907,0.035 -0.246958,0.0575 -0.367865,0.0974 l 0,-0.005 c -2.505594,0.74703 -4.849122,1.83885 -6.984279,3.21799 l 0.0051,0.0125 z"
style="fill:#dd8808;fill-opacity:1" />
<path
id="path4156"
d="m 82.28518,934.25596 16.01368,7.75514 c 0.55308,0.26733 1.139601,0.39475 1.71841,0.39475 1.41744,0 2.78085,-0.76202 3.45741,-2.0737 0.94925,-1.85384 0.17493,-4.10493 -1.73385,-5.02685 l -19.72576,-9.55401 c -0.0437,-0.02 -0.0849,-0.0275 -0.12863,-0.0475 -0.0437,-0.0175 -0.0797,-0.0475 -0.12605,-0.065 -0.0772,-0.03 -0.15949,-0.0425 -0.23924,-0.0675 -0.12862,-0.0425 -0.25467,-0.0824 -0.38073,-0.10993 -0.1209,-0.0275 -0.23924,-0.0425 -0.36014,-0.055 -0.1312,-0.015 -0.2624,-0.03 -0.39102,-0.035 -0.12091,-0.003 -0.23924,0.005 -0.36015,0.0125 -0.12862,0.007 -0.25467,0.02 -0.38072,0.0425 -0.11834,0.02 -0.2341,0.05 -0.34986,0.0774 -0.12348,0.0325 -0.24181,0.0625 -0.36272,0.10744 -0.11319,0.045 -0.22123,0.0924 -0.32928,0.14491 -0.11319,0.0525 -0.2238,0.10743 -0.33185,0.16989 -0.10547,0.06 -0.20322,0.13492 -0.30098,0.20487 -0.10032,0.0725 -0.19551,0.14741 -0.28812,0.22986 -0.0952,0.0824 -0.1775,0.17239 -0.26496,0.26483 -0.0823,0.0924 -0.16207,0.17989 -0.23924,0.27733 -0.0746,0.10243 -0.14406,0.21486 -0.21094,0.32729 -0.0437,0.0675 -0.0952,0.13242 -0.13377,0.20487 -0.0232,0.04 -0.0309,0.085 -0.0514,0.12742 -0.0206,0.045 -0.0489,0.0775 -0.0643,0.11993 l -3.32107,7.84508 c 2.48501,0.77702 4.84397,1.82636 7.01257,3.15552 l 1.87277,-4.42722 z"
style="fill:#dd8808;fill-opacity:1" />
<path
id="path4154"
d="m 25.639199,989.21152 c 0.848918,-2.44597 1.877909,-4.76701 3.045814,-6.99312 -6.554675,-1.81636 -12.576847,-6.09118 -16.890894,-9.55401 -1.646386,-1.31917 -4.0773782,-1.09431 -5.4330752,0.49719 -1.358268,1.5965 -1.126745,3.95752 0.514496,5.27419 4.7153532,3.79263 11.2443042,8.4622 18.7636592,10.77575 z"
style="fill:#dd8808;fill-opacity:1" />
<path
id="path4152"
d="m 102.35823,989.21652 c 7.52192,-2.31355 14.05345,-6.98812 18.77137,-10.77825 1.64382,-1.31667 1.87277,-3.68269 0.51193,-5.27419 -1.35313,-1.5965 -3.79184,-1.81886 -5.43051,-0.49719 -4.31919,3.47032 -10.34136,7.74514 -16.896039,9.55901 1.165339,2.2236 2.194329,4.54965 3.043249,6.99062 z"
style="fill:#dd8808;fill-opacity:1" />
<path
id="path4150"
d="m 102.35823,1025.0616 c -0.84635,2.441 -1.87534,4.767 -3.045819,6.9931 6.557249,1.8114 12.581989,6.0862 16.896039,9.554 0.71772,0.5796 1.58979,0.8595 2.45672,0.8595 1.11131,0 2.21233,-0.4647 2.97636,-1.3567 1.35569,-1.5965 1.12674,-3.9575 -0.5145,-5.2791 -4.71793,-3.7877 -11.24688,-8.4622 -18.7688,-10.7708 z"
style="fill:#dd8808;fill-opacity:1" />
<path
id="path4148"
d="m 123.14128,1003.3876 -17.93532,0 c 0.0823,1.2442 0.16207,2.4884 0.16207,3.7526 0,1.2642 -0.0797,2.5035 -0.16207,3.7427 l 17.93532,0 c 2.13001,0 3.85872,-1.679 3.85872,-3.7477 0,-2.0687 -1.72871,-3.7476 -3.85872,-3.7476 z"
style="fill:#dd8808;fill-opacity:1" />
<path
id="path4144"
d="m 22.624254,1007.1402 c 0,-1.2642 0.07975,-2.5084 0.164638,-3.7526 l -17.9301752,0 c -2.130012,0 -3.858718,1.6789 -3.858718,3.7476 0,2.0687 1.728706,3.7477 3.858718,3.7477 l 17.9327482,0 c -0.08746,-1.2392 -0.167211,-2.481 -0.167211,-3.7427 z"
style="fill:#dd8808;fill-opacity:1" />
<path
id="path4"
d="m 6.8729678,1035.8324 c -1.643814,1.3216 -1.875337,3.6851 -0.514496,5.2791 0.761454,0.892 1.867619,1.3567 2.9763584,1.3567 0.8643518,0 1.7364228,-0.2823 2.4567168,-0.8595 4.316619,-3.4703 10.336218,-7.7401 16.890894,-9.554 -1.167905,-2.2261 -2.196897,-4.5521 -3.045815,-6.9931 -7.516782,2.3136 -14.048305,6.9831 -18.7636582,10.7708 z"
style="fill:#dd8808;fill-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -7,7 +7,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
@ -15,41 +14,10 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="diff.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4136">
<stop
style="stop-color:#34ae3d;stop-opacity:1;"
offset="0"
id="stop4138" />
<stop
style="stop-color:#27812d;stop-opacity:1"
offset="1"
id="stop4140" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4136"
id="linearGradient4142"
x1="18.439"
y1="46.9435"
x2="46.291"
y2="46.9435"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4136"
id="linearGradient4150"
x1="18.438999"
y1="46.943501"
x2="46.291"
y2="46.943501"
gradientUnits="userSpaceOnUse" />
</defs>
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -57,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="-10.424833"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -122,14 +90,14 @@
inkscape:connector-curvature="0"
d="m 97.75685,950.20353 -29.611681,0 -23.709931,-24.84123 -23.747868,0 c -10.8726981,0 -19.6873739,8.81466 -19.6873739,19.68737 l 0,61.78533 c 0,10.8728 8.8146758,19.6875 19.6873739,19.6875 l 33.305003,0 c 0.111101,0 0.218131,-0.015 0.327874,-0.018 l 0,5.1701 c 0,10.8714 8.814675,19.6874 19.687373,19.6874 l 33.30501,0 c 10.87269,0 19.68737,-8.816 19.68737,-19.6874 l 0,-50.83407 -29.24315,-30.63734 z m -76.576314,66.70757 c -5.435672,0 -9.844363,-4.4073 -9.844363,-9.8444 l 0,-61.85172 c 0,-5.43703 4.407337,-9.84437 9.844363,-9.84437 l 18.210583,0 c 2.717835,0 4.922182,2.20299 4.922182,4.92219 l 0,9.31731 c 0,2.71784 2.202991,4.92218 4.922181,4.92218 l 9.844365,0 c 2.717835,0 4.922181,2.20299 4.922181,4.92218 l 0,35.40507 0,12.20856 c 0,5.437 -4.407337,9.8444 -9.844364,9.8444 l -32.977128,0 z m 96.140394,14.9969 c 0,5.4384 -4.40734,9.8444 -9.84437,9.8444 l -32.975775,0 c -5.437026,0 -9.844364,-4.406 -9.844364,-9.8444 l 0,-8.5383 c 5.423479,-3.5077 9.021969,-9.5951 9.021969,-16.5333 l 0,-46.57986 c 0.270971,-0.023 0.543297,-0.0447 0.821041,-0.0447 l 18.209228,0 c 2.719191,0 4.922181,2.20299 4.922181,4.92218 l 0,9.31868 c 0,2.71784 2.204354,4.92218 4.92218,4.92218 l 9.84438,0 c 2.71918,0 4.92217,2.20304 4.92217,4.92223 l 0,47.61089 z"
id="path8"
style="fill:#3027dd;fill-opacity:1" />
style="fill:#2271d5;fill-opacity:1" />
<polygon
transform="matrix(1.3284504,0,0,1.4015682,2.5047034,916.06764)"
points="29.216,60.143 46.291,46.943 29.216,33.744 29.216,43.31 18.439,43.31 18.439,50.333 29.216,50.333 "
id="polygon4"
style="fill:url(#linearGradient4142);fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
<polygon
style="fill:url(#linearGradient4150);fill-opacity:1.0"
style="fill:#2caf45;fill-opacity:1"
id="polygon4153"
points="18.439,43.31 18.439,50.333 29.216,50.333 29.216,60.143 46.291,46.943 29.216,33.744 29.216,43.31 "
transform="matrix(-1.3284504,0,0,1.4015682,134.4953,948.06764)" />

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="document-encrypt.svg">
<defs
id="defs4">
@ -50,17 +50,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="38.332091"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -114,11 +114,11 @@
<g
transform="matrix(1.3939367,0,0,1.3695651,-5.6968353,-384.43812)"
id="g4"
style="fill:#3027dd;fill-opacity:1">
style="fill:#2271d5;fill-opacity:1">
<path
inkscape:connector-curvature="0"
d="m 20.000054,956.3622 c -1.94862,0.01 -3.01295,1.69 -3,3 l 0,86 c 1.6e-4,1.5708 1.42925,2.9998 3,3 l 60,0 c 1.57075,-2e-4 2.99984,-1.4292 3,-3 l 0,-70 c 0.002,-0.7861 -0.32012,-1.5681 -0.875,-2.125 l -16,-16 c -0.55685,-0.5549 -1.33889,-0.8769 -2.125,-0.875 l -44,0 z m 3,6 38,0 0,13 a 3.0003,3.0003 0 0 0 3,3 l 13,0 0,64 -54,0 0,-80 z m 44,4.2188 5.78125,5.7812 -5.78125,0 0,-5.7812 z"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#3027dd;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#2271d5;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
visibility="visible"
display="inline"
overflow="visible"

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -7,7 +7,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
@ -15,33 +14,10 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="document-import.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4139"
id="linearGradient4145"
x1="25.760529"
y1="988.36218"
x2="102.23947"
y2="988.36218"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.62762378,0,0,0.6386548,23.832078,368.13994)" />
<linearGradient
inkscape:collect="always"
id="linearGradient4139">
<stop
style="stop-color:#557022;stop-opacity:1"
offset="0"
id="stop4141" />
<stop
style="stop-color:#95c43c;stop-opacity:1"
offset="1"
id="stop4143" />
</linearGradient>
</defs>
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -49,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="19.1967"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -113,11 +89,11 @@
<g
transform="matrix(1.3939367,0,0,1.3695651,-5.6968353,-384.43812)"
id="g4"
style="fill:#3027dd;fill-opacity:1">
style="fill:#2271d5;fill-opacity:1">
<path
inkscape:connector-curvature="0"
d="m 20.000054,956.3622 c -1.94862,0.01 -3.01295,1.69 -3,3 l 0,86 c 1.6e-4,1.5708 1.42925,2.9998 3,3 l 60,0 c 1.57075,-2e-4 2.99984,-1.4292 3,-3 l 0,-70 c 0.002,-0.7861 -0.32012,-1.5681 -0.875,-2.125 l -16,-16 c -0.55685,-0.5549 -1.33889,-0.8769 -2.125,-0.875 l -44,0 z m 3,6 38,0 0,13 a 3.0003,3.0003 0 0 0 3,3 l 13,0 0,64 -54,0 0,-80 z m 44,4.2188 5.78125,5.7812 -5.78125,0 0,-5.7812 z"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#3027dd;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#2271d5;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
visibility="visible"
display="inline"
overflow="visible"
@ -127,6 +103,6 @@
inkscape:connector-curvature="0"
d="m 87.119695,974.32745 -24.602319,25.03473 24.602319,25.03472 Q 88,1025.2927 88,1026.5185 q 0,1.2258 -0.880305,2.1217 l -7.691123,7.8262 q -0.880309,0.8958 -2.084942,0.8958 -1.204633,0 -2.084943,-0.8958 L 40.880312,1001.4838 Q 40,1000.588 40,999.36218 q 0,-1.2258 0.880312,-2.12159 l 34.378375,-34.98261 q 0.88031,-0.89578 2.084943,-0.89578 1.204633,0 2.084942,0.89578 l 7.691123,7.82631 Q 88,970.98006 88,972.20587 q 0,1.2258 -0.880305,2.12158 z"
id="path4"
style="fill:url(#linearGradient4145);fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -7,7 +7,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
@ -15,34 +14,10 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="document-new.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4142">
<stop
style="stop-color:#34ae3d;stop-opacity:1;"
offset="0"
id="stop4144" />
<stop
style="stop-color:#26822e;stop-opacity:1"
offset="1"
id="stop4146" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4142"
id="radialGradient4148"
cx="64"
cy="999.36214"
fx="64"
fy="999.36214"
r="29"
gradientTransform="matrix(1,0,0,1.0000021,0,-0.00206765)"
gradientUnits="userSpaceOnUse" />
</defs>
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -57,10 +32,10 @@
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -114,11 +89,11 @@
<g
transform="matrix(1.3939367,0,0,1.3695651,-5.6968353,-384.43812)"
id="g4"
style="fill:#3027dd;fill-opacity:1">
style="fill:#2271d5;fill-opacity:1">
<path
inkscape:connector-curvature="0"
d="m 20.000054,956.3622 c -1.94862,0.01 -3.01295,1.69 -3,3 l 0,86 c 1.6e-4,1.5708 1.42925,2.9998 3,3 l 60,0 c 1.57075,-2e-4 2.99984,-1.4292 3,-3 l 0,-70 c 0.002,-0.7861 -0.32012,-1.5681 -0.875,-2.125 l -16,-16 c -0.55685,-0.5549 -1.33889,-0.8769 -2.125,-0.875 l -44,0 z m 3,6 38,0 0,13 a 3.0003,3.0003 0 0 0 3,3 l 13,0 0,64 -54,0 0,-80 z m 44,4.2188 5.78125,5.7812 -5.78125,0 0,-5.7812 z"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#3027dd;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#2271d5;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
visibility="visible"
display="inline"
overflow="visible"
@ -128,6 +103,6 @@
inkscape:connector-curvature="0"
d="m 93,995.40757 0,7.90913 q 0,1.6479 -1.153415,2.801 -1.1534,1.1535 -2.801125,1.1535 l -17.13637,0 0,17.1366 q 0,1.6475 -1.153401,2.8009 -1.153414,1.1535 -2.801139,1.1535 l -7.90909,0 q -1.647735,0 -2.801139,-1.1535 -1.153411,-1.1534 -1.153411,-2.8009 l 0,-17.1366 -17.13636,0 q -1.647725,0 -2.801135,-1.1535 Q 35,1004.9646 35,1003.3167 l 0,-7.90913 q 0,-1.6477 1.153415,-2.8011 1.15341,-1.1535 2.801135,-1.1535 l 17.13636,0 0,-17.13635 q 0,-1.64771 1.153411,-2.80112 1.153404,-1.15342 2.801139,-1.15342 l 7.90909,0 q 1.647725,0 2.801139,1.15342 1.153401,1.15341 1.153401,2.80112 l 0,17.13635 17.13637,0 q 1.647725,0 2.801125,1.1535 Q 93,993.75987 93,995.40757 Z"
id="path4"
style="fill:url(#radialGradient4148);fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -7,7 +7,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
@ -15,43 +14,10 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="document-split.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4141"
id="linearGradient4147"
x1="64.402176"
y1="1023.1872"
x2="63.597828"
y2="953.27203"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.3265309,0,0,-0.3265309,43.102023,1283.843)" />
<linearGradient
inkscape:collect="always"
id="linearGradient4141">
<stop
style="stop-color:#016324;stop-opacity:1"
offset="0"
id="stop4143" />
<stop
style="stop-color:#16fb67;stop-opacity:1"
offset="1"
id="stop4145" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4141"
id="linearGradient4157"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.3265309,0,0,0.3265309,43.102023,691.95274)"
x1="64.402176"
y1="1023.1872"
x2="63.597828"
y2="953.27203" />
</defs>
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -66,10 +32,10 @@
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -125,7 +91,7 @@
overflow="visible"
display="inline"
visibility="visible"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#3027dd;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#2271d5;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
d="m 22.181976,924.64788 c -2.716253,0.0137 -4.199861,2.31457 -4.18181,4.1087 l 0,53.22899 c 2.23e-4,2.1513 1.992284,4.1085 4.18181,4.1087 l 83.636194,0 c 2.18953,-2e-4 4.18159,-1.9574 4.18181,-4.1087 l 0,-31.31595 c 0.003,-1.07662 -0.44623,-2.14762 -1.21969,-2.91033 L 86.477307,925.84625 c -0.77621,-0.75997 -1.86633,-1.20097 -2.96212,-1.19837 z m 4.18181,8.21739 52.969595,0 0,17.80435 c 2.34e-4,2.26907 1.872355,4.10846 4.181806,4.10869 l 18.121173,0 0,23.09856 -75.272574,0 z m 61.333211,5.77792 8.0587,7.91773 -8.0587,0 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccccccccc" />
@ -133,7 +99,7 @@
sodipodi:nodetypes="cccccccccccccc"
inkscape:connector-curvature="0"
d="m 22.18198,990.27288 c -2.716253,0.0137 -4.199861,2.31457 -4.18181,4.1087 l 0,53.22902 c 2.23e-4,2.1513 1.992284,4.1085 4.18181,4.1087 l 83.6362,0 c 2.18953,-2e-4 4.18159,-1.9574 4.18181,-4.1087 l -0.21907,-53.19292 c -0.005,-1.88755 -0.90332,-4.04296 -3.14069,-4.05551 z m 4.18181,8.21739 74.66602,0 0.60656,45.01163 -75.27258,0 z"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#3027dd;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#2271d5;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
visibility="visible"
display="inline"
overflow="visible"
@ -142,9 +108,9 @@
inkscape:connector-curvature="0"
d="m 84.244916,970.00105 q 0,-1.03174 -0.751276,-1.7857 L 65.779338,950.43753 Q 65.028063,949.68357 64,949.68357 q -1.028062,0 -1.779338,0.75396 L 44.50636,968.21535 q -0.751276,0.75396 -0.751276,1.7857 0,1.03177 0.751276,1.7857 0.751277,0.75399 1.779339,0.75399 l 35.428602,0 q 1.028063,0 1.779339,-0.75399 0.751275,-0.75393 0.751275,-1.7857 z"
id="path4"
style="fill:url(#linearGradient4147);fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
<path
style="fill:url(#linearGradient4157);fill-opacity:1"
style="fill:#2caf45;fill-opacity:1"
id="path4155"
d="m 84.244916,1005.7947 q 0,1.0317 -0.751276,1.7857 l -17.714302,17.7778 q -0.751275,0.754 -1.779338,0.754 -1.028062,0 -1.779338,-0.754 L 44.50636,1007.5804 q -0.751276,-0.754 -0.751276,-1.7857 0,-1.0318 0.751276,-1.7857 0.751277,-0.754 1.779339,-0.754 l 35.428602,0 q 1.028063,0 1.779339,0.754 0.751275,0.7539 0.751275,1.7857 z"
inkscape:connector-curvature="0" />

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="document_open.svg">
<defs
id="defs4" />
@ -25,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="8.0642339"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -86,19 +86,15 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36216)">
<g
id="g4152"
transform="translate(95.31562,26.03569)">
<path
style="fill:#3027dd;fill-opacity:1"
inkscape:connector-curvature="0"
d="m 29.929313,974.80653 c -1.587443,-2.02757 -4.087204,-3.04531 -6.685793,-3.04531 l -92.131013,0 c -4.627058,0 -8.133024,2.79574 -9.368384,7.20513 0,0 0,-0.16617 0,-0.16556 l -12.79591,46.52571 107.224081,0 c 2.205125,0 4.135382,-1.6265 4.694385,-3.7283 L 31.41175,981.98368 c 0.659685,-2.4768 0.105624,-5.14959 -1.482437,-7.17715 z"
id="path6-6" />
<path
style="fill:#1c168e;fill-opacity:1"
inkscape:connector-curvature="0"
d="m -68.887493,967.50035 16.838636,0 3.520788,0 2.391666,0 0,-60.52687 c 0,-2.32704 3.251479,-2.16878 3.657297,-2.16878 l 42.3242049,0 c 1.229805,0.6087 1.580031,0.36096 1.580031,1.59235 l 0,8.90765 c 0,2.83531 2.821573,6.54348 5.737033,6.54348 l 7.4387471,0 c 1.361372,0 2.266276,-0.39322 2.266276,1.14922 l 0,44.50295 4.941458,0 0,-47.44478 c 0,-1.92165 -0.195187,-4.36922 -2.031557,-6.2513 L 7.6871929,901.62609 c -1.597326,-1.63739 -3.665944,-2.29965 -6.366451,-2.29965 l -43.7998479,0 c -4.601733,0 -9.216437,2.75861 -9.216437,7.64704 l 0,31.42757 c -4.323776,-0.5387 -8.42951,-1.9107 -10.14852,-6.02791 -1.030294,-2.46887 -3.200211,-4.438 -5.909366,-4.438 l -21.052468,0 c -2.92163,0 -5.509723,2.26861 -5.509723,5.14774 l 0,7.03104 0,1.13583 0,76.97325 10.921863,-40.15873 c 1.71777,-6.44122 7.748202,-10.56392 14.506264,-10.56392 z"
id="path8" />
</g>
<path
id="path6-6"
d="m 125.24493,1000.8422 c -1.58744,-2.02755 -4.0872,-3.04529 -6.68579,-3.04529 H 26.428127 c -4.627058,0 -8.133024,2.79579 -9.368384,7.20509 0,0 0,-0.1661 0,-0.1655 l -12.79591,46.5257 H 111.48791 c 2.20513,0 4.13539,-1.6265 4.69439,-3.7283 l 10.54507,-39.6145 c 0.65969,-2.4768 0.10562,-5.1496 -1.48244,-7.1772 z"
inkscape:connector-curvature="0"
style="fill:#3027dd;fill-opacity:1" />
<path
id="path8"
d="m 26.428127,993.53604 h 16.838636 3.520788 2.391666 v -60.52687 c 0,-2.32704 3.251479,-2.16878 3.657297,-2.16878 h 42.324205 c 1.229805,0.6087 1.580031,0.36096 1.580031,1.59235 v 8.90765 c 0,2.83531 2.821573,6.54348 5.73703,6.54348 h 7.43875 c 1.36137,0 2.26628,-0.39322 2.26628,1.14922 v 44.50295 h 4.94145 v -47.44478 c 0,-1.92165 -0.19518,-4.36922 -2.03155,-6.2513 l -12.0899,-12.17818 c -1.59732,-1.63739 -3.665941,-2.29965 -6.366448,-2.29965 H 52.836514 c -4.601733,0 -9.216437,2.75861 -9.216437,7.64704 v 31.42757 c -4.323776,-0.5387 -8.42951,-1.9107 -10.14852,-6.02791 -1.030294,-2.46887 -3.200211,-4.438 -5.909366,-4.438 H 6.509723 C 3.588093,953.97083 1,956.23944 1,959.11857 v 7.03104 1.13583 76.97326 L 11.921863,1004.1 c 1.71777,-6.44126 7.748202,-10.56396 14.506264,-10.56396 z"
inkscape:connector-curvature="0"
style="fill:#2271d5;fill-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="edit-clear.svg">
<defs
id="defs4">
@ -71,17 +71,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="30.132813"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -144,7 +144,7 @@
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssscc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4.02708244;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
style="fill:none;fill-rule:evenodd;stroke:#2271d5;stroke-width:4.02708244;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="m 9.6415558,1036.8579 83.8879072,0"
id="path4223"
inkscape:connector-curvature="0" />

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="edit-cut.svg">
<defs
id="defs4" />
@ -25,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="-38.266034"
inkscape:zoom="5.656854"
inkscape:cx="102.11588"
inkscape:cy="95.08399"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -94,7 +94,7 @@
d="m 68.495532,983.86336 q 1.82763,0 3.1632,1.3356 1.33557,1.3356 1.33557,3.1632 0,1.8276 -1.33557,3.1632 -1.33557,1.3356 -3.1632,1.3356 -1.82763,0 -3.1632,-1.3356 -1.33557,-1.3356 -1.33557,-3.1632 0,-1.8276 1.33557,-3.1632 1.33557,-1.3356 3.1632,-1.3356 z m 21.088,4.4988 35.638728,27.97674 q 1.96821,1.4059 1.75733,3.9365 -0.35146,2.4602 -2.46026,3.5849 l -8.99755,4.4988 q -0.91382,0.4921 -2.03851,0.4921 -1.19499,0 -2.17909,-0.5624 l -48.502408,-27.2035 -7.73227,4.6393 q -0.56234,0.2812 -0.84352,0.3515 0.98411,3.4444 0.70294,6.8185 -0.49206,5.4126 -3.93643,10.3682 -3.44438,4.9557 -9.27872,8.6813 -9.27873,5.9046 -19.47126,5.9046 -9.5599,0 -15.6051202,-5.4829 -6.32639997,-5.9046 -5.55318,-14.5507 0.49206,-5.3423 3.93643,-10.3331 3.44437,-4.9909 9.2084302,-8.71644 9.27872,-5.9046 19.54155,-5.9046 5.83435,0 10.61429,2.1791 0.63264,-0.9139 1.54646,-1.5465 l 8.57579,-5.1314 -8.57579,-5.1314 q -0.91382,-0.6327 -1.54646,-1.5465 -4.77994,2.1791 -10.61429,2.1791 -10.26283,0 -19.54155,-5.9046 -5.7640602,-3.7256 -9.2084302,-8.7164 -3.44437,-4.9908 -3.93643,-10.3331 -0.35145997,-4.1473 1.08955,-7.9432 1.44101,-3.7958 4.46363,-6.5373 5.9749302,-5.5531 15.6051202,-5.5531 10.19253,0 19.47126,5.9046 5.83434,3.6553 9.27872,8.6461 3.44437,4.9908 3.93643,10.4034 0.28117,3.3741 -0.70294,6.8185 0.28118,0.07 0.84352,0.3514 l 7.73227,4.6394 48.502408,-27.2035 q 0.9841,-0.5624 2.17909,-0.5624 1.12469,0 2.03851,0.4921 l 8.99755,4.4987 q 2.1088,1.1247 2.46026,3.585 0.21088,2.5306 -1.75733,3.9364 z m -47.86976,-18.2763 q 3.23349,-2.9523 1.47616,-7.5917 -1.75734,-4.6393 -7.4511,-8.2243 -6.46699,-4.1473 -13.49632,-4.1473 -5.20171,0 -7.94315,2.5306 -3.23349,2.9523 -1.47616,7.5916 1.75734,4.6394 7.4511,8.2244 6.46698,4.1473 13.49632,4.1473 5.20171,0 7.94315,-2.5306 z m -5.97494,52.36864 q 5.69376,-3.585 7.4511,-8.2244 1.75733,-4.6393 -1.47616,-7.5916 -2.74144,-2.5306 -7.94315,-2.5306 -7.02934,0 -13.49632,4.1473 -5.69376,3.585 -7.4511,8.2243 -1.75733,4.6394 1.47616,7.5917 2.74144,2.5306 7.94315,2.5306 7.02933,0 13.49632,-4.1473 z m 12.51222,-43.08994 6.74816,4.0771 0,-0.7733 q 0,-2.5305 2.31968,-3.9364 l 0.98411,-0.5623 -5.55318,-3.3038 -1.82763,1.8276 q -0.21088,0.2109 -0.70293,0.7732 -0.49205,0.5624 -0.84352,0.8435 -0.14059,0.1406 -0.28117,0.2461 -0.14059,0.1054 -0.21088,0.1757 z m 15.74571,15.7457 6.74816,2.2494 51.735898,-40.4889 -8.99755,-4.4988 -53.985288,30.2964 0,7.9432 -11.24693,6.7481 0.63264,0.5624 q 0.14058,0.1406 0.49205,0.4217 0.28117,0.2812 0.77323,0.8436 0.49205,0.5623 0.77322,0.84354 l 1.82763,1.8276 z m 49.486508,29.24214 8.99755,-4.4988 -36.552538,-28.67974 -12.44192,9.70054 q -0.14059,0.2109 -0.91382,0.4921 z"
id="path4-3"
inkscape:connector-curvature="0"
style="fill:#160a02;fill-opacity:1" />
style="fill:#888888;fill-opacity:1" />
<path
style="fill:#ea8404;fill-opacity:1"
inkscape:connector-curvature="0"

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="edit-paste.svg">
<defs
id="defs4">
@ -69,17 +69,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="19.843024"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -135,7 +135,7 @@
d="m 55,1897.4872 63,0 0,-45 -29.25,0 q -2.8125,0 -4.78125,-1.9687 Q 82,1848.5497 82,1845.7372 l 0,-29.25 -27,0 0,81 z m 18,-101.25 0,-4.5 q 0,-0.9141 -0.66797,-1.582 -0.66797,-0.668 -1.58203,-0.668 l -49.5,0 q -0.91406,0 -1.58203,0.668 Q 19,1790.8231 19,1791.7372 l 0,4.5 q 0,0.9141 0.66797,1.582 0.66797,0.668 1.58203,0.668 l 49.5,0 q 0.91406,0 1.58203,-0.668 Q 73,1797.1513 73,1796.2372 Z m 18,47.25 21.02344,0 L 91,1822.4638 l 0,21.0234 z m 36,9 0,47.25 q 0,2.8125 -1.96875,4.7813 -1.96875,1.9687 -4.78125,1.9687 l -67.5,0 q -2.8125,0 -4.78125,-1.9687 Q 46,1902.5497 46,1899.7372 l 0,-11.25 -38.25,0 q -2.8125,0 -4.78125,-1.9687 Q 1,1884.5497 1,1881.7372 l 0,-94.5 q 0,-2.8125 1.96875,-4.7813 1.96875,-1.9687 4.78125,-1.9687 l 76.5,0 q 2.8125,0 4.78125,1.9687 Q 91,1784.4247 91,1787.2372 l 0,23.0625 q 1.47656,0.9141 2.53125,1.9687 l 28.6875,28.6875 q 1.96875,1.9688 3.375,5.3438 1.40625,3.375 1.40625,6.1875 z"
id="path4" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#3c3c3c;fill-opacity:1;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 35.477134,925.36215 -4.081555,12.29269 34.477134,0 -4.081555,-12.29269 -26.314024,0 z"
id="path4162" />
<path
@ -147,7 +147,7 @@
d="m 53.243902,968.38655 0,82.97565 67.609758,0 0,-55.31712 -24.585367,0 a 3.0734781,3.0734781 0 0 1 -3.07317,-3.07317 l 0,-24.58536 -39.951221,0 z"
id="path4158" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#3c3c3c;fill-opacity:1;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#686868;fill-opacity:1;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 99.341464,968.38655 0,21.51219 21.512196,0 -21.512196,-21.51219 z"
id="path6" />
</g>

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="edit-select-all.svg">
<defs
id="defs4">
@ -23,11 +23,11 @@
inkscape:collect="always"
id="linearGradient4142">
<stop
style="stop-color:#545ada;stop-opacity:1;"
style="stop-color:#b2cffa;stop-opacity:1"
offset="0"
id="stop4144" />
<stop
style="stop-color:#23289f;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="1"
id="stop4146" />
</linearGradient>
@ -48,17 +48,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="19.843024"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -115,7 +115,7 @@
id="path4"
style="fill:url(#linearGradient4148);fill-opacity:1" />
<path
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#30a82d;stroke-width:3.94074321;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:3.94074312, 11.82222935;stroke-dashoffset:0;stroke-opacity:1"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#2caf45;stroke-width:3.94074321;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:3.94074312, 11.82222935000000064;stroke-dashoffset:0;stroke-opacity:1"
d="m 2.970371,927.33253 122.059259,0 0,122.05927 -122.059259,0 z"
id="rect4139"
inkscape:connector-curvature="0" />

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="edit_input.svg">
<defs
id="defs4" />
@ -25,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="-10.424833"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -105,29 +105,28 @@
transform="matrix(1.4835039,0,0,1.4904899,-11.62087,914.96969)"
style="fill-opacity:1;fill:#ea8404" />
</g>
<path
id="path12"
d="m 112.20127,973.84851 v 64.10449 c 0,4.9186 -4.00546,8.9429 -8.90103,8.9429 H 14.356767 c -4.8955631,0 -8.9010236,-4.0243 -8.9010236,-8.9429 v -88.94052 c 0,-4.91862 4.0054605,-8.94294 8.9010236,-8.94294 h 64.643682"
inkscape:connector-curvature="0"
style="fill:none;fill-opacity:1;stroke:#2271d5;stroke-width:8.92195702;stroke-opacity:1" />
<g
transform="matrix(1.4835039,0,0,1.4904899,-11.62087,914.96969)"
id="g10"
style="fill:none;fill-opacity:1;stroke:#3244c4;stroke-opacity:1">
<path
style="fill:none;stroke:#3244c4;stroke-width:6;fill-opacity:1;stroke-opacity:1"
inkscape:connector-curvature="0"
d="m 83.466,39.503 0,43.009 c 0,3.3 -2.7,6 -6,6 l -59.955,0 c -3.3,0 -6,-2.7 -6,-6 l 0,-59.672 c 0,-3.3 2.7,-6 6,-6 l 43.575,0"
id="path12" />
id="g823"
style="stroke:#2caf45;stroke-opacity:1">
<line
id="line14"
y2="1018.5588"
x2="92.966148"
y1="1018.5588"
x1="24.724976"
style="fill:none;stroke:#2caf45;stroke-width:4.46097851;stroke-opacity:1" />
<line
id="line16"
y2="1030.4828"
x2="92.966148"
y1="1030.4828"
x1="24.724976"
style="fill:none;stroke:#2caf45;stroke-width:4.46097851;stroke-opacity:1" />
</g>
<line
style="fill:none;stroke:#000000;stroke-width:4.46097851"
x1="24.724976"
y1="1018.5588"
x2="92.966148"
y2="1018.5588"
id="line14" />
<line
style="fill:none;stroke:#000000;stroke-width:4.46097851"
x1="24.724976"
y1="1030.4828"
x2="92.966148"
y2="1030.4828"
id="line16" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -7,7 +7,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
@ -15,45 +14,10 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="embed-fonts.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4142">
<stop
style="stop-color:#34ae3d;stop-opacity:1;"
offset="0"
id="stop4144" />
<stop
style="stop-color:#26822e;stop-opacity:1"
offset="1"
id="stop4146" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4142"
id="radialGradient4153"
cx="-66.893486"
cy="971.11334"
fx="-66.893486"
fy="971.11334"
r="3.9624026"
gradientTransform="matrix(1,0,0,1.2615541,0,-253.99865)"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4142"
id="radialGradient4155"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,1.2615541,0,-253.99865)"
cx="-66.893486"
cy="971.11334"
fx="-66.893486"
fy="971.11334"
r="3.9624026" />
</defs>
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -61,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="6.1653019"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -125,25 +89,25 @@
<g
transform="matrix(1.3939367,0,0,1.3695651,-5.6968353,-384.43812)"
id="g4"
style="fill:#3027dd;fill-opacity:1">
style="fill:#2271d5;fill-opacity:1">
<path
inkscape:connector-curvature="0"
d="m 20.000054,956.3622 c -1.94862,0.01 -3.01295,1.69 -3,3 l 0,86 c 1.6e-4,1.5708 1.42925,2.9998 3,3 l 60,0 c 1.57075,-2e-4 2.99984,-1.4292 3,-3 l 0,-70 c 0.002,-0.7861 -0.32012,-1.5681 -0.875,-2.125 l -16,-16 c -0.55685,-0.5549 -1.33889,-0.8769 -2.125,-0.875 l -44,0 z m 3,6 38,0 0,13 a 3.0003,3.0003 0 0 0 3,3 l 13,0 0,64 -54,0 0,-80 z m 44,4.2188 5.78125,5.7812 -5.78125,0 0,-5.7812 z"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#3027dd;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#2271d5;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
visibility="visible"
display="inline"
overflow="visible"
id="path6" />
</g>
<g
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Cambria;-inkscape-font-specification:Cambria;letter-spacing:0px;word-spacing:0px;fill:url(#radialGradient4153);fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Cambria;-inkscape-font-specification:Cambria;letter-spacing:0px;word-spacing:0px;fill:#2caf45;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text4140"
transform="matrix(5.8045592,0,0,5.6013611,452.2872,-4439.1944)">
<path
d="m -70.855888,966.11462 7.924804,0 0,2.54883 -0.717773,0 q -0.161133,-0.62988 -0.322266,-0.99609 -0.153808,-0.36621 -0.32959,-0.55664 -0.175781,-0.19043 -0.380859,-0.271 -0.197754,-0.0806 -0.600586,-0.0806 l -0.930176,0 0,7.5 q 0,0.43212 0.04395,0.68847 0.05127,0.25635 0.146484,0.41016 0.102539,0.14648 0.270996,0.23437 0.168457,0.0806 0.527344,0.16114 l 0,0.35888 -3.347168,0 0,-0.35888 q 0.219726,-0.0513 0.388183,-0.10987 0.168458,-0.0586 0.270997,-0.13916 0.109863,-0.0879 0.175781,-0.21972 0.07324,-0.13184 0.109863,-0.35889 0.04394,-0.22705 0.04394,-0.6665 l 0,-7.5 -0.922851,0 q -0.344238,0 -0.571289,0.0659 -0.219727,0.0659 -0.410156,0.27832 -0.19043,0.20508 -0.351563,0.59327 -0.153809,0.38085 -0.292969,0.96679 l -0.725097,0 0,-2.54883 z"
id="path4145"
inkscape:connector-curvature="0"
style="fill:url(#radialGradient4155);fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="folder_saved_search.svg">
<defs
id="defs4" />
@ -25,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="68.276786"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -95,11 +95,11 @@
id="path8"
d="m 26.428127,993.53604 16.838636,0 3.520788,0 2.391666,0 0,-60.52687 c 0,-2.32704 3.251479,-2.16878 3.657297,-2.16878 l 42.324205,0 c 1.229805,0.6087 1.580031,0.36096 1.580031,1.59235 l 0,8.90765 c 0,2.83531 2.821573,6.54348 5.73703,6.54348 l 7.43875,0 c 1.36137,0 2.26628,-0.39322 2.26628,1.14922 l 0,44.50295 4.94145,0 0,-47.44478 c 0,-1.92165 -0.19518,-4.36922 -2.03155,-6.2513 l -12.0899,-12.17818 c -1.59732,-1.63739 -3.665941,-2.29965 -6.366448,-2.29965 l -43.799848,0 c -4.601733,0 -9.216437,2.75861 -9.216437,7.64704 l 0,31.42757 c -4.323776,-0.5387 -8.42951,-1.9107 -10.14852,-6.02791 -1.030294,-2.46887 -3.200211,-4.438 -5.909366,-4.438 l -21.052468,0 C 3.588093,953.97083 1,956.23944 1,959.11857 l 0,7.03104 0,1.13583 0,76.97326 10.921863,-40.1587 c 1.71777,-6.44126 7.748202,-10.56396 14.506264,-10.56396 z"
inkscape:connector-curvature="0"
style="fill:#1c168e;fill-opacity:1" />
style="fill:#2271d5;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
d="m 95.489615,975.4847 -11.935263,-9.67724 c -0.430099,-0.32257 -0.645149,-0.96772 -0.322574,-1.50535 2.365547,-5.05367 1.505348,-11.18259 -2.688123,-15.37606 -5.591294,-5.59129 -15.053484,-5.26872 -20.214679,1.18278 -3.870896,4.83862 -3.870896,11.82773 -0.107524,16.77388 4.085945,5.16119 10.967538,6.45149 16.451307,3.8709 0.537625,-0.21505 1.075249,-0.10753 1.505349,0.32257 l 9.67724,11.93524 c 1.505348,1.82792 4.193471,1.93545 5.806344,0.32258 l 2.258023,-2.25803 c 1.505348,-1.3978 1.397823,-4.08592 -0.4301,-5.59127 z m -17.311507,-9.56971 c -3.978421,3.97842 -10.537439,3.97842 -14.623385,0 -3.978421,-3.97843 -3.978421,-10.53744 0,-14.62339 3.978421,-4.08594 10.537439,-3.97842 14.623385,0 4.085946,4.08595 4.085946,10.64496 0,14.62339 z"
id="path6"
style="fill:#261fb5;fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -15,8 +15,9 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="font.svg">
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="font.svg"
enable-background="new">
<defs
id="defs4">
<linearGradient
@ -72,6 +73,16 @@
result="composite2"
id="feComposite4298" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter1038">
<feBlend
inkscape:collect="always"
mode="overlay"
in2="BackgroundImage"
id="feBlend1040" />
</filter>
</defs>
<sodipodi:namedview
id="base"
@ -80,17 +91,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:cx="19.843024"
inkscape:zoom="7.919596"
inkscape:cx="-12.10305"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -163,22 +174,22 @@
id="polyline14" />
<g
id="g4167"
style="fill:#6d0b0b;fill-opacity:1;filter:url(#filter4288)">
style="fill:#dd8808;fill-opacity:1;filter:url(#filter1038)">
<path
id="path4"
d="m 17.470144,999.2509 -7.005639,0 0,-4.98468 20.050489,0 0,4.98468 -7.12241,0 0,21.2627 -5.92244,0 0,-21.2627 z"
inkscape:connector-curvature="0"
style="fill:#6d0b0b;fill-opacity:1" />
style="fill:#dd8808;fill-opacity:1" />
<path
id="path6"
d="m 58.629806,994.26622 15.947361,0 0,4.86785 -10.024922,0 0,5.99723 9.367518,0 0,4.8276 -9.367518,0 0,10.5541 -5.922439,0 0,-26.24678 z"
inkscape:connector-curvature="0"
style="fill:#6d0b0b;fill-opacity:1" />
style="fill:#dd8808;fill-opacity:1" />
<path
id="path16"
d="m 41.341832,999.2509 -7.005639,0 0,-4.98468 20.050488,0 0,4.98468 -7.12241,0 0,21.2627 -5.922439,0 0,-21.2627 z"
inkscape:connector-curvature="0"
style="fill:#6d0b0b;fill-opacity:1" />
style="fill:#dd8808;fill-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="font_size_larger.svg">
<defs
id="defs4">
@ -113,17 +113,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="47.159598"
inkscape:cy="72.481885"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -174,30 +174,34 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36216)">
<g
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:90px;line-height:125%;font-family:Calibri;-inkscape-font-specification:Calibri;letter-spacing:0px;word-spacing:0px;fill:#261fb5;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
id="text4133"
transform="matrix(1.4074832,0,0,1.4146743,-44.275876,-351.59006)">
<path
d="m 121.33301,973.61005 q 0.35156,0.96679 0.35156,1.58203 0.044,0.57129 -0.30762,0.8789 -0.35156,0.30762 -1.18652,0.39551 -0.79102,0.0879 -2.15332,0.0879 -1.36231,0 -2.19727,-0.0879 -0.79101,-0.0439 -1.23046,-0.17578 -0.39551,-0.17578 -0.61524,-0.43945 -0.17578,-0.26367 -0.35156,-0.65918 l -4.87793,-13.84278 -23.64258,0 -4.658203,13.667 q -0.131836,0.3955 -0.351562,0.70312 -0.219727,0.26367 -0.65918,0.4834 -0.395508,0.17578 -1.186523,0.26367 -0.747071,0.0879 -1.97754,0.0879 -1.274414,0 -2.109375,-0.13183 -0.791015,-0.0879 -1.142578,-0.39551 -0.307617,-0.30762 -0.307617,-0.87891 0.04395,-0.61523 0.395508,-1.58203 l 19.072266,-52.82226 q 0.175781,-0.4834 0.439453,-0.79102 0.307617,-0.30762 0.834961,-0.4834 0.571289,-0.17578 1.40625,-0.21973 0.878906,-0.0879 2.197265,-0.0879 1.40625,0 2.329102,0.0879 0.922853,0.0439 1.494143,0.21973 0.57129,0.17578 0.8789,0.52735 0.30762,0.30761 0.4834,0.79101 l 19.07227,52.82227 z m -24.477541,-46.62598 -0.04395,0 -9.799804,28.34473 19.775395,0 -9.931645,-28.34473 z"
id="path4140"
inkscape:connector-curvature="0"
style="fill:#261fb5;fill-opacity:1" />
</g>
<path
d="M 2.3203367,970.6888 32.772366,939.97452 C 33.614358,939.11738 34.737013,938.6888 36,938.6888 c 1.262988,0 2.385643,0.42858 3.227635,1.28572 l 30.452029,30.71428 c 1.262987,1.28572 1.683983,3.28572 0.982323,5.14286 -0.70166,1.71428 -2.385643,2.85714 -4.209958,2.85714 l -60.9040579,0 c -1.8243151,0 -3.5082982,-1.14286 -4.2099579,-2.85714 -0.70165963,-1.71429 -0.2806639,-3.71429 0.9823235,-5.14286 z"
id="path4145"
style="fill:url(#linearGradient4149);fill-opacity:1"
inkscape:connector-curvature="0" />
<g
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Calibri;-inkscape-font-specification:Calibri;letter-spacing:0px;word-spacing:0px;fill:#261fb5;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
id="text4151"
transform="matrix(4.0418484,0,0,4.0418484,-38.501788,-3022.6663)">
<path
d="m 22.196219,1002.0939 q 0.05859,0.1612 0.05859,0.2637 0.0073,0.095 -0.05127,0.1465 -0.05859,0.051 -0.197754,0.066 -0.131836,0.015 -0.358887,0.015 -0.227051,0 -0.366211,-0.015 -0.131836,-0.01 -0.205078,-0.029 -0.06592,-0.029 -0.102539,-0.073 -0.0293,-0.044 -0.05859,-0.1099 l -0.812988,-2.3071 -3.94043,0 -0.776367,2.2778 q -0.02197,0.066 -0.05859,0.1172 -0.03662,0.044 -0.109863,0.081 -0.06592,0.029 -0.197754,0.044 -0.124512,0.015 -0.32959,0.015 -0.212402,0 -0.351562,-0.022 -0.131836,-0.015 -0.19043,-0.066 -0.05127,-0.051 -0.05127,-0.1465 0.0073,-0.1026 0.06592,-0.2637 l 3.178711,-8.8037 q 0.0293,-0.0806 0.07324,-0.13184 0.05127,-0.0513 0.13916,-0.0806 0.09521,-0.0293 0.234375,-0.0366 0.146484,-0.0146 0.366211,-0.0146 0.234375,0 0.388183,0.0146 0.153809,0.007 0.249024,0.0366 0.09521,0.0293 0.146484,0.0879 0.05127,0.0513 0.08057,0.13183 l 3.17871,8.80371 z m -4.079589,-7.77096 -0.0073,0 -1.6333,4.72412 3.295898,0 -1.655273,-4.72412 z"
id="path4156"
inkscape:connector-curvature="0"
style="fill:#261fb5;fill-opacity:1" />
id="g837"
style="fill:#2271d5;fill-opacity:1">
<g
transform="matrix(1.4074832,0,0,1.4146743,-44.275876,-351.59006)"
id="text4133"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:90px;line-height:125%;font-family:Calibri;-inkscape-font-specification:Calibri;letter-spacing:0px;word-spacing:0px;fill:#2271d5;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1">
<path
style="fill:#2271d5;fill-opacity:1"
inkscape:connector-curvature="0"
id="path4140"
d="m 121.33301,973.61005 q 0.35156,0.96679 0.35156,1.58203 0.044,0.57129 -0.30762,0.8789 -0.35156,0.30762 -1.18652,0.39551 -0.79102,0.0879 -2.15332,0.0879 -1.36231,0 -2.19727,-0.0879 -0.79101,-0.0439 -1.23046,-0.17578 -0.39551,-0.17578 -0.61524,-0.43945 -0.17578,-0.26367 -0.35156,-0.65918 l -4.87793,-13.84278 -23.64258,0 -4.658203,13.667 q -0.131836,0.3955 -0.351562,0.70312 -0.219727,0.26367 -0.65918,0.4834 -0.395508,0.17578 -1.186523,0.26367 -0.747071,0.0879 -1.97754,0.0879 -1.274414,0 -2.109375,-0.13183 -0.791015,-0.0879 -1.142578,-0.39551 -0.307617,-0.30762 -0.307617,-0.87891 0.04395,-0.61523 0.395508,-1.58203 l 19.072266,-52.82226 q 0.175781,-0.4834 0.439453,-0.79102 0.307617,-0.30762 0.834961,-0.4834 0.571289,-0.17578 1.40625,-0.21973 0.878906,-0.0879 2.197265,-0.0879 1.40625,0 2.329102,0.0879 0.922853,0.0439 1.494143,0.21973 0.57129,0.17578 0.8789,0.52735 0.30762,0.30761 0.4834,0.79101 l 19.07227,52.82227 z m -24.477541,-46.62598 -0.04395,0 -9.799804,28.34473 19.775395,0 -9.931645,-28.34473 z" />
</g>
<g
transform="matrix(4.0418484,0,0,4.0418484,-38.501788,-3022.6663)"
id="text4151"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Calibri;-inkscape-font-specification:Calibri;letter-spacing:0px;word-spacing:0px;fill:#2271d5;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1">
<path
style="fill:#2271d5;fill-opacity:1"
inkscape:connector-curvature="0"
id="path4156"
d="m 22.196219,1002.0939 q 0.05859,0.1612 0.05859,0.2637 0.0073,0.095 -0.05127,0.1465 -0.05859,0.051 -0.197754,0.066 -0.131836,0.015 -0.358887,0.015 -0.227051,0 -0.366211,-0.015 -0.131836,-0.01 -0.205078,-0.029 -0.06592,-0.029 -0.102539,-0.073 -0.0293,-0.044 -0.05859,-0.1099 l -0.812988,-2.3071 -3.94043,0 -0.776367,2.2778 q -0.02197,0.066 -0.05859,0.1172 -0.03662,0.044 -0.109863,0.081 -0.06592,0.029 -0.197754,0.044 -0.124512,0.015 -0.32959,0.015 -0.212402,0 -0.351562,-0.022 -0.131836,-0.015 -0.19043,-0.066 -0.05127,-0.051 -0.05127,-0.1465 0.0073,-0.1026 0.06592,-0.2637 l 3.178711,-8.8037 q 0.0293,-0.0806 0.07324,-0.13184 0.05127,-0.0513 0.13916,-0.0806 0.09521,-0.0293 0.234375,-0.0366 0.146484,-0.0146 0.366211,-0.0146 0.234375,0 0.388183,0.0146 0.153809,0.007 0.249024,0.0366 0.09521,0.0293 0.146484,0.0879 0.05127,0.0513 0.08057,0.13183 l 3.17871,8.80371 z m -4.079589,-7.77096 -0.0073,0 -1.6333,4.72412 3.295898,0 -1.655273,-4.72412 z" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="font_size_smaller.svg">
<defs
id="defs4">
@ -113,17 +113,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="16.891741"
inkscape:cy="72.481885"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -177,27 +177,31 @@
<g
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:90px;line-height:125%;font-family:Calibri;-inkscape-font-specification:Calibri;letter-spacing:0px;word-spacing:0px;fill:#261fb5;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
id="text4133"
transform="matrix(1.4074832,0,0,1.4146743,-44.275876,-351.59006)">
<path
d="m 121.33301,973.61005 q 0.35156,0.96679 0.35156,1.58203 0.044,0.57129 -0.30762,0.8789 -0.35156,0.30762 -1.18652,0.39551 -0.79102,0.0879 -2.15332,0.0879 -1.36231,0 -2.19727,-0.0879 -0.79101,-0.0439 -1.23046,-0.17578 -0.39551,-0.17578 -0.61524,-0.43945 -0.17578,-0.26367 -0.35156,-0.65918 l -4.87793,-13.84278 -23.64258,0 -4.658203,13.667 q -0.131836,0.3955 -0.351562,0.70312 -0.219727,0.26367 -0.65918,0.4834 -0.395508,0.17578 -1.186523,0.26367 -0.747071,0.0879 -1.97754,0.0879 -1.274414,0 -2.109375,-0.13183 -0.791015,-0.0879 -1.142578,-0.39551 -0.307617,-0.30762 -0.307617,-0.87891 0.04395,-0.61523 0.395508,-1.58203 l 19.072266,-52.82226 q 0.175781,-0.4834 0.439453,-0.79102 0.307617,-0.30762 0.834961,-0.4834 0.571289,-0.17578 1.40625,-0.21973 0.878906,-0.0879 2.197265,-0.0879 1.40625,0 2.329102,0.0879 0.922853,0.0439 1.494143,0.21973 0.57129,0.17578 0.8789,0.52735 0.30762,0.30761 0.4834,0.79101 l 19.07227,52.82227 z m -24.477541,-46.62598 -0.04395,0 -9.799804,28.34473 19.775395,0 -9.931645,-28.34473 z"
id="path4140"
inkscape:connector-curvature="0"
style="fill:#261fb5;fill-opacity:1" />
</g>
transform="matrix(1.4074832,0,0,1.4146743,-44.275876,-351.59006)" />
<path
d="m 2.3203367,946.6888 30.4520293,30.71428 c 0.841992,0.85714 1.964647,1.28572 3.227634,1.28572 1.262988,0 2.385643,-0.42858 3.227635,-1.28572 L 69.679664,946.6888 c 1.262987,-1.28572 1.683983,-3.28572 0.982323,-5.14286 -0.70166,-1.71428 -2.385643,-2.85714 -4.209958,-2.85714 l -60.9040579,0 c -1.8243151,0 -3.5082982,1.14286 -4.2099579,2.85714 -0.70165963,1.71429 -0.2806639,3.71429 0.9823235,5.14286 z"
id="path4145"
style="fill:url(#linearGradient4149);fill-opacity:1"
inkscape:connector-curvature="0" />
<g
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Calibri;-inkscape-font-specification:Calibri;letter-spacing:0px;word-spacing:0px;fill:#261fb5;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
id="text4151"
transform="matrix(4.0418484,0,0,4.0418484,-38.501788,-3022.6663)">
id="g837"
style="fill:#2271d5;fill-opacity:1">
<path
d="m 22.196219,1002.0939 q 0.05859,0.1612 0.05859,0.2637 0.0073,0.095 -0.05127,0.1465 -0.05859,0.051 -0.197754,0.066 -0.131836,0.015 -0.358887,0.015 -0.227051,0 -0.366211,-0.015 -0.131836,-0.01 -0.205078,-0.029 -0.06592,-0.029 -0.102539,-0.073 -0.0293,-0.044 -0.05859,-0.1099 l -0.812988,-2.3071 -3.94043,0 -0.776367,2.2778 q -0.02197,0.066 -0.05859,0.1172 -0.03662,0.044 -0.109863,0.081 -0.06592,0.029 -0.197754,0.044 -0.124512,0.015 -0.32959,0.015 -0.212402,0 -0.351562,-0.022 -0.131836,-0.015 -0.19043,-0.066 -0.05127,-0.051 -0.05127,-0.1465 0.0073,-0.1026 0.06592,-0.2637 l 3.178711,-8.8037 q 0.0293,-0.0806 0.07324,-0.13184 0.05127,-0.0513 0.13916,-0.0806 0.09521,-0.0293 0.234375,-0.0366 0.146484,-0.0146 0.366211,-0.0146 0.234375,0 0.388183,0.0146 0.153809,0.007 0.249024,0.0366 0.09521,0.0293 0.146484,0.0879 0.05127,0.0513 0.08057,0.13183 l 3.17871,8.80371 z m -4.079589,-7.77096 -0.0073,0 -1.6333,4.72412 3.295898,0 -1.655273,-4.72412 z"
id="path4156"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:90px;line-height:125%;font-family:Calibri;-inkscape-font-specification:Calibri;letter-spacing:0px;word-spacing:0px;fill:#2271d5;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0"
style="fill:#261fb5;fill-opacity:1" />
id="path4140"
d="m 121.33301,973.61005 q 0.35156,0.96679 0.35156,1.58203 0.044,0.57129 -0.30762,0.8789 -0.35156,0.30762 -1.18652,0.39551 -0.79102,0.0879 -2.15332,0.0879 -1.36231,0 -2.19727,-0.0879 -0.79101,-0.0439 -1.23046,-0.17578 -0.39551,-0.17578 -0.61524,-0.43945 -0.17578,-0.26367 -0.35156,-0.65918 l -4.87793,-13.84278 -23.64258,0 -4.658203,13.667 q -0.131836,0.3955 -0.351562,0.70312 -0.219727,0.26367 -0.65918,0.4834 -0.395508,0.17578 -1.186523,0.26367 -0.747071,0.0879 -1.97754,0.0879 -1.274414,0 -2.109375,-0.13183 -0.791015,-0.0879 -1.142578,-0.39551 -0.307617,-0.30762 -0.307617,-0.87891 0.04395,-0.61523 0.395508,-1.58203 l 19.072266,-52.82226 q 0.175781,-0.4834 0.439453,-0.79102 0.307617,-0.30762 0.834961,-0.4834 0.571289,-0.17578 1.40625,-0.21973 0.878906,-0.0879 2.197265,-0.0879 1.40625,0 2.329102,0.0879 0.922853,0.0439 1.494143,0.21973 0.57129,0.17578 0.8789,0.52735 0.30762,0.30761 0.4834,0.79101 l 19.07227,52.82227 z m -24.477541,-46.62598 -0.04395,0 -9.799804,28.34473 19.775395,0 -9.931645,-28.34473 z"
transform="matrix(1.4074832,0,0,1.4146743,-44.275876,-351.59004)" />
<g
transform="matrix(4.0418484,0,0,4.0418484,-38.501788,-3022.6663)"
id="text4151"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Calibri;-inkscape-font-specification:Calibri;letter-spacing:0px;word-spacing:0px;fill:#2271d5;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1">
<path
style="fill:#2271d5;fill-opacity:1"
inkscape:connector-curvature="0"
id="path4156"
d="m 22.196219,1002.0939 q 0.05859,0.1612 0.05859,0.2637 0.0073,0.095 -0.05127,0.1465 -0.05859,0.051 -0.197754,0.066 -0.131836,0.015 -0.358887,0.015 -0.227051,0 -0.366211,-0.015 -0.131836,-0.01 -0.205078,-0.029 -0.06592,-0.029 -0.102539,-0.073 -0.0293,-0.044 -0.05859,-0.1099 l -0.812988,-2.3071 -3.94043,0 -0.776367,2.2778 q -0.02197,0.066 -0.05859,0.1172 -0.03662,0.044 -0.109863,0.081 -0.06592,0.029 -0.197754,0.044 -0.124512,0.015 -0.32959,0.015 -0.212402,0 -0.351562,-0.022 -0.131836,-0.015 -0.19043,-0.066 -0.05127,-0.051 -0.05127,-0.1465 0.0073,-0.1026 0.06592,-0.2637 l 3.178711,-8.8037 q 0.0293,-0.0806 0.07324,-0.13184 0.05127,-0.0513 0.13916,-0.0806 0.09521,-0.0293 0.234375,-0.0366 0.146484,-0.0146 0.366211,-0.0146 0.234375,0 0.388183,0.0146 0.153809,0.007 0.249024,0.0366 0.09521,0.0293 0.146484,0.0879 0.05127,0.0513 0.08057,0.13183 l 3.17871,8.80371 z m -4.079589,-7.77096 -0.0073,0 -1.6333,4.72412 3.295898,0 -1.655273,-4.72412 z" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-fill-color.svg">
<defs
id="defs4" />
@ -25,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="19.843024"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -86,51 +86,47 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36216)">
<g
transform="translate(0.00260059,0.00376367)"
id="g4140">
<path
id="path4"
d="m 40.013479,999.06915 c 6.359757,4.67475 20.124993,-3.15171 30.748644,-17.46631 l 33.295197,33.61766 c -10.626597,14.3161 -20.771572,17.651 -27.134275,12.9792"
stroke-miterlimit="10"
style="fill:#bc3e4c;fill-opacity:1;stroke:#000000;stroke-width:4.40812302;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:10"
inkscape:connector-curvature="0" />
<ellipse
id="ellipse6"
ry="32.282364"
rx="14.290408"
cy="-748.86212"
cx="-616.16022"
stroke-miterlimit="10"
transform="matrix(-0.8058623,-0.592103,0.59573364,-0.80318206,0,0)"
style="fill:none;stroke:#000000;stroke-width:4.40800762;stroke-miterlimit:10" />
<path
id="path8"
d="m 85.46409,977.45432 c 3.178405,-2.48472 6.266967,-5.64375 9.022665,-9.36276 0.785028,-1.05546 1.517033,-2.1285 2.198962,-3.20448 7.602843,-12.04097 8.679493,-24.85155 2.075243,-29.70811 -5.9886,-4.40066 -16.413416,-0.87222 -25.244612,7.869"
stroke-miterlimit="10"
style="fill:none;stroke:#000000;stroke-width:5.8774972;stroke-linecap:round;stroke-miterlimit:10"
inkscape:connector-curvature="0" />
<path
id="path10"
d="m 31.182284,992.23215 56.121393,44.06525 c 5.727905,4.2086 18.116023,-2.8366 27.674813,-15.719 9.55141,-12.8912 12.66501,-26.74548 6.94153,-30.94971 L 69.644231,940.36975"
stroke-miterlimit="10"
style="fill:none;stroke:#000000;stroke-width:4.40812302;stroke-miterlimit:10"
inkscape:connector-curvature="0" />
<path
style="fill:#37b63b;fill-opacity:1"
id="path12"
d="m 64.359653,971.28577 c -12.75928,-0.0748 -27.904574,4.3303 -33.175896,7.31929 -5.26985,2.98899 -12.095026,8.47882 -15.822804,14.98012 -3.729251,6.50422 -5.051868,17.33732 -0.29457,24.86472 0,0 6.227201,9.4258 7.65439,19.0671 0.768827,3.1928 -1.322617,7.4981 5.275741,8.7647 6.596886,1.2695 4.73226,-12.8912 4.73226,-12.8912 0,0 -0.631851,-3.8085 -1.543544,-7.9101 -1.624551,-9.263 4.813266,-29.4706 4.813266,-29.4706 0,0 1.857261,-2.08159 6.938586,-4.3347 2.947169,-1.27241 8.386396,-5.52794 8.386396,-5.52794 l 5.857515,-5.61883 4.755826,-5.76395 c -0.0044,0 1.281377,-1.66674 2.422834,-3.47861 z"
inkscape:connector-curvature="0" />
<path
style="fill:#3a37b6;fill-opacity:1"
id="path14"
d="m 24.801907,980.76288 c 0,0 -21.867371,-2.08306 -20.6728915,6.1231 1.1959525,8.20616 7.2611395,3.59148 10.3364455,-1.19032 3.073834,-4.78326 10.336446,-4.93278 10.336446,-4.93278 z"
inkscape:connector-curvature="0" />
<path
style="fill:#3a37b6;fill-opacity:1"
id="path16"
d="m 15.670251,989.86324 c 0,0 -19.2648493,10.50616 -13.6415164,16.62636 5.6233329,6.1187 8.0343844,-1.0877 7.87679,-6.76666 -0.1575947,-5.676 5.7647264,-9.8597 5.7647264,-9.8597 z"
inkscape:connector-curvature="0" />
</g>
<path
inkscape:connector-curvature="0"
style="fill:#bc3e4c;fill-opacity:1;stroke:#000000;stroke-width:4.40812302;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:10"
stroke-miterlimit="10"
d="m 40.01608,999.07291 c 6.359757,4.67479 20.124993,-3.15171 30.748644,-17.46631 l 33.295196,33.6177 c -10.626596,14.3161 -20.771571,17.651 -27.134274,12.9792"
id="path4" />
<ellipse
style="fill:none;stroke:#dba50a;stroke-width:4.40800762;stroke-miterlimit:10;stroke-opacity:1"
transform="matrix(-0.8058623,-0.592103,0.59573364,-0.80318206,0,0)"
stroke-miterlimit="10"
cx="-616.16455"
cy="-748.86359"
rx="14.290408"
ry="32.282364"
id="ellipse6" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#dba50a;stroke-width:5.8774972;stroke-linecap:round;stroke-miterlimit:10;fill-opacity:1;stroke-opacity:1"
stroke-miterlimit="10"
d="m 85.466691,977.45808 c 3.178405,-2.48472 6.266967,-5.64375 9.022665,-9.36276 0.785028,-1.05546 1.517033,-2.1285 2.198962,-3.20448 7.602842,-12.04097 8.679492,-24.85155 2.075243,-29.70811 -5.9886,-4.40066 -16.413416,-0.87222 -25.244612,7.869"
id="path8" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#dba50a;stroke-width:4.40812302;stroke-miterlimit:10;stroke-opacity:1"
stroke-miterlimit="10"
d="m 31.184885,992.23591 56.121393,44.06529 c 5.727905,4.2086 18.116022,-2.8366 27.674812,-15.719 9.55141,-12.8912 12.66501,-26.74552 6.94153,-30.94975 L 69.646832,940.37351"
id="path10" />
<path
inkscape:connector-curvature="0"
d="m 64.362254,971.28953 c -12.75928,-0.0748 -27.904574,4.3303 -33.175896,7.31929 -5.26985,2.98899 -12.095026,8.47882 -15.822804,14.98012 -3.729251,6.50426 -5.051868,17.33736 -0.29457,24.86476 0,0 6.227201,9.4258 7.65439,19.0671 0.768827,3.1928 -1.322617,7.4981 5.275741,8.7647 6.596886,1.2695 4.73226,-12.8912 4.73226,-12.8912 0,0 -0.631851,-3.8085 -1.543544,-7.9101 -1.624551,-9.263 4.813266,-29.47064 4.813266,-29.47064 0,0 1.857261,-2.08159 6.938586,-4.3347 2.947169,-1.27241 8.386396,-5.52794 8.386396,-5.52794 l 5.857515,-5.61883 4.755826,-5.76395 c -0.0044,0 1.281377,-1.66674 2.422834,-3.47861 z"
id="path12"
style="fill:#37b63b;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
d="m 24.804508,980.76664 c 0,0 -21.8673714,-2.08306 -20.6728919,6.1231 1.1959525,8.20616 7.2611399,3.59148 10.3364459,-1.19032 3.073834,-4.78326 10.336446,-4.93278 10.336446,-4.93278 z"
id="path14"
style="fill:#2271d5;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
d="m 15.672852,989.867 c 0,0 -19.2648497,10.5062 -13.6415168,16.6264 5.6233329,6.1187 8.0343848,-1.0877 7.87679,-6.7667 -0.1575947,-5.676 5.7647268,-9.8597 5.7647268,-9.8597 z"
id="path16"
style="fill:#2271d5;fill-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -7,7 +7,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
@ -15,51 +14,10 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-indent-less.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4178">
<stop
style="stop-color:#0a4da3;stop-opacity:1"
offset="0"
id="stop4180" />
<stop
style="stop-color:#041f42;stop-opacity:1"
offset="1"
id="stop4182" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4178"
id="linearGradient4205"
gradientUnits="userSpaceOnUse"
x1="3.25"
y1="988.36218"
x2="127"
y2="988.36218"
gradientTransform="matrix(1.2741702,0,0,1.3174597,91.323232,-313.85451)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4178"
id="linearGradient4207"
gradientUnits="userSpaceOnUse"
x1="3.25"
y1="988.36218"
x2="127"
y2="988.36218" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4178"
id="linearGradient4209"
gradientUnits="userSpaceOnUse"
x1="3.25"
y1="988.36218"
x2="127"
y2="988.36218" />
</defs>
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -67,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="57.130788"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -131,22 +89,23 @@
<path
d="m 127,1022.1122 0,13.5 q 0,0.9141 -0.66797,1.582 -0.66797,0.668 -1.58203,0.668 l -121.5,0 q -0.91406,0 -1.58203,-0.668 Q 1,1036.5263 1,1035.6122 l 0,-13.5 q 0,-0.9141 0.66797,-1.582 0.66797,-0.668 1.58203,-0.668 l 121.5,0 q 0.91406,0 1.58203,0.668 0.66797,0.6679 0.66797,1.582 z"
id="path4145"
style="fill:#041f42;fill-opacity:1" />
style="fill:#2271d5;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
d="m 127,961.59431 0,53.35729 q 0,1.2042 -0.85111,2.0841 -0.85111,0.8801 -2.01577,0.8801 -1.25426,0 -2.06057,-0.8337 L 96.270594,990.40347 q -0.806308,-0.8337 -0.806308,-2.13061 0,-1.2969 0.806308,-2.13059 l 25.801956,-26.67856 q 0.80631,-0.83369 2.06057,-0.83369 1.16466,0 2.01577,0.88007 Q 127,960.39002 127,961.59431 Z"
id="path4147"
style="fill:url(#linearGradient4205);fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
<g
id="g4144"
transform="translate(-45,0)">
transform="translate(-45,0)"
style="fill:#2271d5;fill-opacity:1">
<path
style="fill:url(#linearGradient4207);fill-opacity:1"
style="fill:#2271d5;fill-opacity:1"
id="path4143"
d="m 127,995.11216 0,13.50004 q 0,0.9141 -0.66797,1.582 -0.66797,0.668 -1.58203,0.668 l -76.5,0 q -0.91406,0 -1.58203,-0.668 Q 46,1009.5263 46,1008.6122 l 0,-13.50004 q 0,-0.9141 0.66797,-1.582 0.66797,-0.668 1.58203,-0.668 l 76.5,0 q 0.91406,0 1.58203,0.668 0.66797,0.6679 0.66797,1.582 z"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient4209);fill-opacity:1"
style="fill:#2271d5;fill-opacity:1"
id="path4141"
d="m 127,968.11216 0,13.5 q 0,0.9141 -0.66797,1.582 -0.66797,0.668 -1.58203,0.668 l -76.5,0 q -0.91406,0 -1.58203,-0.668 Q 46,982.52626 46,981.61216 l 0,-13.5 q 0,-0.9141 0.66797,-1.582 0.66797,-0.668 1.58203,-0.668 l 76.5,0 q 0.91406,0 1.58203,0.668 0.66797,0.6679 0.66797,1.582 z"
inkscape:connector-curvature="0" />
@ -154,6 +113,6 @@
<path
d="m 127,941.11216 0,13.5 q 0,0.9141 -0.66797,1.582 -0.66797,0.668 -1.58203,0.668 l -121.5,0 q -0.91406,0 -1.58203,-0.668 Q 1,955.52626 1,954.61216 l 0,-13.5 q 0,-0.9141 0.66797,-1.582 0.66797,-0.668 1.58203,-0.668 l 121.5,0 q 0.91406,0 1.58203,0.668 0.66797,0.6679 0.66797,1.582 z"
id="path4"
style="fill-opacity:1;fill:#041f42" />
style="fill-opacity:1;fill:#2271d5" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -7,7 +7,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
@ -15,51 +14,10 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-indent-more.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4178">
<stop
style="stop-color:#0a4da3;stop-opacity:1"
offset="0"
id="stop4180" />
<stop
style="stop-color:#041f42;stop-opacity:1"
offset="1"
id="stop4182" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4178"
id="linearGradient4205"
gradientUnits="userSpaceOnUse"
x1="3.25"
y1="988.36218"
x2="127"
y2="988.36218"
gradientTransform="matrix(-1.2741702,0,0,1.3174597,36.676768,-313.85451)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4178"
id="linearGradient4207"
gradientUnits="userSpaceOnUse"
x1="3.25"
y1="988.36218"
x2="127"
y2="988.36218" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4178"
id="linearGradient4209"
gradientUnits="userSpaceOnUse"
x1="3.25"
y1="988.36218"
x2="127"
y2="988.36218" />
</defs>
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -67,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="26.862931"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -131,21 +89,22 @@
<path
d="m 127,1022.1122 0,13.5 q 0,0.9141 -0.66797,1.582 -0.66797,0.668 -1.58203,0.668 l -121.5,0 q -0.91406,0 -1.58203,-0.668 Q 1,1036.5263 1,1035.6122 l 0,-13.5 q 0,-0.9141 0.66797,-1.582 0.66797,-0.668 1.58203,-0.668 l 121.5,0 q 0.91406,0 1.58203,0.668 0.66797,0.6679 0.66797,1.582 z"
id="path4145"
style="fill:#041f42;fill-opacity:1" />
style="fill:#2271d5;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
d="m 1,961.59431 0,53.35729 q 0,1.2042 0.85111,2.0841 0.85111,0.8801 2.01577,0.8801 1.25426,0 2.06057,-0.8337 l 25.801956,-26.67863 q 0.806308,-0.8337 0.806308,-2.13061 0,-1.2969 -0.806308,-2.13059 L 5.92745,959.46371 q -0.80631,-0.83369 -2.06057,-0.83369 -1.16466,0 -2.01577,0.88007 Q 1,960.39002 1,961.59431 Z"
id="path4147"
style="fill:url(#linearGradient4205);fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
<g
id="g4144">
id="g4144"
style="fill:#2271d5;fill-opacity:1">
<path
style="fill:url(#linearGradient4207);fill-opacity:1"
style="fill:#2271d5;fill-opacity:1"
id="path4143"
d="m 127,995.11216 0,13.50004 q 0,0.9141 -0.66797,1.582 -0.66797,0.668 -1.58203,0.668 l -76.5,0 q -0.91406,0 -1.58203,-0.668 Q 46,1009.5263 46,1008.6122 l 0,-13.50004 q 0,-0.9141 0.66797,-1.582 0.66797,-0.668 1.58203,-0.668 l 76.5,0 q 0.91406,0 1.58203,0.668 0.66797,0.6679 0.66797,1.582 z"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient4209);fill-opacity:1"
style="fill:#2271d5;fill-opacity:1"
id="path4141"
d="m 127,968.11216 0,13.5 q 0,0.9141 -0.66797,1.582 -0.66797,0.668 -1.58203,0.668 l -76.5,0 q -0.91406,0 -1.58203,-0.668 Q 46,982.52626 46,981.61216 l 0,-13.5 q 0,-0.9141 0.66797,-1.582 0.66797,-0.668 1.58203,-0.668 l 76.5,0 q 0.91406,0 1.58203,0.668 0.66797,0.6679 0.66797,1.582 z"
inkscape:connector-curvature="0" />
@ -153,6 +112,6 @@
<path
d="m 127,941.11216 0,13.5 q 0,0.9141 -0.66797,1.582 -0.66797,0.668 -1.58203,0.668 l -121.5,0 q -0.91406,0 -1.58203,-0.668 Q 1,955.52626 1,954.61216 l 0,-13.5 q 0,-0.9141 0.66797,-1.582 0.66797,-0.668 1.58203,-0.668 l 121.5,0 q 0.91406,0 1.58203,0.668 0.66797,0.6679 0.66797,1.582 z"
id="path4"
style="fill-opacity:1;fill:#041f42" />
style="fill-opacity:1;fill:#2271d5" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-justify-center.svg">
<defs
id="defs4">
@ -23,15 +23,15 @@
inkscape:collect="always"
id="linearGradient4139">
<stop
style="stop-color:#08387a;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="0"
id="stop4141" />
<stop
id="stop4147"
offset="0.50773352"
style="stop-color:#0d5cc6;stop-opacity:1" />
style="stop-color:#b2cffa;stop-opacity:1" />
<stop
style="stop-color:#08397a;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="1"
id="stop4143" />
</linearGradient>
@ -52,17 +52,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="15.309153"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-justify-fill.svg">
<defs
id="defs4">
@ -23,15 +23,15 @@
inkscape:collect="always"
id="linearGradient4139">
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
style="stop-color:#b2cffa;stop-opacity:1"
offset="0"
id="stop4141" />
<stop
id="stop4147"
offset="0.51573128"
style="stop-color:#08397a;stop-opacity:1" />
style="stop-color:#0b59bd;stop-opacity:1" />
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
style="stop-color:#b2cffa;stop-opacity:1"
offset="1"
id="stop4143" />
</linearGradient>
@ -52,17 +52,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="49.38296"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-justify-left.svg">
<defs
id="defs4">
@ -23,11 +23,11 @@
inkscape:collect="always"
id="linearGradient4139">
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
style="stop-color:#b2cffa;stop-opacity:1"
offset="0"
id="stop4141" />
<stop
style="stop-color:#083a7c;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="1"
id="stop4143" />
</linearGradient>
@ -48,17 +48,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="23.828721"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-justify-right.svg">
<defs
id="defs4">
@ -23,11 +23,11 @@
inkscape:collect="always"
id="linearGradient4139">
<stop
style="stop-color:#08397a;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="0"
id="stop4141" />
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
style="stop-color:#b2cffa;stop-opacity:1"
offset="1"
id="stop4143" />
</linearGradient>
@ -48,17 +48,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="-10.424833"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -15,19 +15,19 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="chapters.svg">
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-list-ordered.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4165">
<stop
style="stop-color:#116def;stop-opacity:1"
style="stop-color:#b2cffa;stop-opacity:1"
offset="0"
id="stop4167" />
<stop
style="stop-color:#020e1e;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="1"
id="stop4169" />
</linearGradient>
@ -48,17 +48,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="19.843024"
inkscape:zoom="5.656854"
inkscape:cx="-24.881482"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -111,19 +111,19 @@
transform="translate(0,-924.36216)">
<g
id="g4155"
style="fill:#116def;fill-opacity:1">
style="fill:#2caf45;fill-opacity:1">
<path
id="path4149"
d="m 28.258393,1037.5797 q 0,5.4724 -3.728101,8.619 -3.728102,3.1466 -9.26888,3.1466 -7.2509858,0 -11.7656771,-4.5147 l 3.899039,-6.0196 q 3.3518541,3.0782 7.2509851,3.0782 1.983707,0 3.454417,-0.9919 1.47071,-0.9919 1.47071,-2.9072 0,-4.3779 -7.182518,-3.8307 l -1.77849,-3.8307 q 0.547185,-0.6841 2.223112,-2.9756 1.675927,-2.2916 2.907232,-3.6939 1.231304,-1.4023 2.530984,-2.6336 l 0,-0.068 q -1.094462,0 -3.317667,0.068 -2.223112,0.068 -3.317666,0.068 l 0,3.6254 -7.2508934,0 0,-10.3976 22.7788594,0 0,6.0197 -6.498491,7.8665 q 3.488696,0.8209 5.540871,3.3519 2.052174,2.531 2.052174,6.0197 z"
style="fill:#116def;fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
<path
id="path4147"
d="m 28.395143,994.68968 0,10.87642 -24.7626581,0 q -0.4104349,-2.4626 -0.4104349,-3.6939 0,-3.48869 1.607552,-6.36165 1.6075521,-2.87304 3.8648515,-4.65153 2.2573915,-1.77858 4.5147835,-3.24929 2.257392,-1.47071 3.864852,-2.97561 1.607552,-1.50489 1.607552,-3.07826 0,-1.71011 -0.9919,-2.63355 -0.991807,-0.92352 -2.702014,-0.92352 -3.146637,0 -5.5407787,3.96751 l -5.8144634,-4.03589 q 1.6417395,-3.48869 4.8910311,-5.43821 3.249199,-1.94952 7.216706,-1.94952 4.993593,0 8.413822,2.83876 3.420229,2.83886 3.420229,7.69561 0,3.42023 -2.325766,6.25909 -2.325767,2.83876 -5.130344,4.41213 -2.804669,1.57327 -5.164624,3.45441 -2.359954,1.88115 -2.428329,3.59126 l 8.687415,0 0,-4.10426 7.182518,0 z"
style="fill:#116def;fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
<path
id="path4143"
d="m 28.463611,955.01471 0,6.77209 -22.9157941,0 0,-6.77209 7.3193601,0 q 0,-2.80457 0.03419,-8.34545 0.03419,-5.54077 0.03419,-8.27698 l 0,-0.82087 -0.136842,0 q -0.547277,1.16284 -3.4202291,3.69392 l -4.8567512,-5.19881 9.3030673,-8.68751 7.250893,0 0,27.6357 7.387828,0 z"
style="fill:#116def;fill-opacity:1" />
style="fill:#2caf45;fill-opacity:1" />
</g>
<g
id="g4160"

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -15,67 +15,31 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-list-unordered.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4165">
id="linearGradient848">
<stop
style="stop-color:#116def;stop-opacity:1"
style="stop-color:#b2cffa;stop-opacity:1"
offset="0"
id="stop4167" />
id="stop844" />
<stop
style="stop-color:#020e1e;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="1"
id="stop4169" />
id="stop846" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4165"
id="linearGradient4158"
gradientUnits="userSpaceOnUse"
x1="77.170937"
y1="944.39056"
x2="77.170937"
y2="1032.3369" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4165"
id="linearGradient4160"
gradientUnits="userSpaceOnUse"
x1="77.170937"
y1="944.39056"
x2="77.170937"
y2="1032.3369" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4165"
id="linearGradient4162"
gradientUnits="userSpaceOnUse"
x1="77.170937"
y1="944.39056"
x2="77.170937"
y2="1032.3369" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4165"
id="linearGradient4164"
gradientUnits="userSpaceOnUse"
x1="77.170937"
y1="944.39056"
x2="77.170937"
y2="1032.3369" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4165"
id="linearGradient4166"
gradientUnits="userSpaceOnUse"
x1="77.170937"
y1="944.39056"
x2="77.170937"
y2="1032.3369" />
xlink:href="#linearGradient848"
id="linearGradient850"
x1="82.474236"
y1="944.56732"
x2="82.705093"
y2="1032.0718"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
@ -84,17 +48,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="70.163491"
inkscape:zoom="5.656854"
inkscape:cx="25.438985"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -145,48 +109,56 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36216)">
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient4158);fill-opacity:1"
d="m 124.77795,1016.5109 0,13.1337 q 0,0.8893 -0.64984,1.5392 -0.64984,0.6499 -1.53908,0.6499 l -83.180612,0 q -0.889337,0 -1.539177,-0.6499 -0.64984,-0.6499 -0.64984,-1.5392 l 0,-13.1337 q 0,-0.9577 0.615652,-1.5734 0.615653,-0.6156 1.573365,-0.6156 l 83.180612,0 q 0.88924,0 1.53908,0.6498 0.64984,0.6499 0.64984,1.5392 z"
id="path4145" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient4160);fill-opacity:1"
d="m 124.77795,981.48749 0,13.13382 q 0,0.88924 -0.64984,1.53908 -0.64984,0.64984 -1.53908,0.64984 l -83.180612,0 q -0.889337,0 -1.539177,-0.64984 -0.64984,-0.64984 -0.64984,-1.53908 l 0,-13.13382 q 0,-0.95772 0.615652,-1.57337 0.615653,-0.61556 1.573365,-0.61556 l 83.180612,0 q 0.88924,0 1.53908,0.64984 0.64984,0.64984 0.64984,1.53909 z"
id="path4141" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient4162);fill-opacity:1"
d="m 124.77795,946.46405 0,13.13382 q 0,0.88925 -0.64984,1.53909 -0.64984,0.64984 -1.53908,0.64984 l -83.180612,0 q -0.889337,0 -1.539177,-0.64984 -0.64984,-0.64984 -0.64984,-1.53909 l 0,-13.13382 q 0,-0.88925 0.64984,-1.53909 0.64984,-0.64984 1.539177,-0.64984 l 83.180612,0 q 0.88924,0 1.53908,0.64984 0.64984,0.64984 0.64984,1.53909 z"
id="path4" />
<path
inkscape:connector-curvature="0"
id="path4150"
d="m 124.77795,946.46405 0,13.13382 q 0,0.88925 -0.64984,1.53909 -0.64984,0.64984 -1.53908,0.64984 l -83.180612,0 q -0.889337,0 -1.539177,-0.64984 -0.64984,-0.64984 -0.64984,-1.53909 l 0,-13.13382 q 0,-0.88925 0.64984,-1.53909 0.64984,-0.64984 1.539177,-0.64984 l 83.180612,0 q 0.88924,0 1.53908,0.64984 0.64984,0.64984 0.64984,1.53909 z"
style="fill:url(#linearGradient4164);fill-opacity:1" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient4166);fill-opacity:1"
d="m 124.77795,946.46405 0,13.13382 q 0,0.88925 -0.64984,1.53909 -0.64984,0.64984 -1.53908,0.64984 l -83.180612,0 q -0.889337,0 -1.539177,-0.64984 -0.64984,-0.64984 -0.64984,-1.53909 l 0,-13.13382 q 0,-0.88925 0.64984,-1.53909 0.64984,-0.64984 1.539177,-0.64984 l 83.180612,0 q 0.88924,0 1.53908,0.64984 0.64984,0.64984 0.64984,1.53909 z"
id="path4154" />
<circle
style="fill:#116def;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4148"
cx="16.484426"
cy="953.03094"
r="11.092738" />
<circle
r="11.092738"
cy="988.05438"
cx="16.484426"
id="circle4152"
style="fill:#116def;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
style="fill:#116def;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle4156"
cx="16.484426"
cy="1023.0778"
r="11.092738" />
<g
id="g842"
style="fill-opacity:1;fill:url(#linearGradient850)">
<path
id="path4145"
d="m 124.77795,1016.5109 0,13.1337 q 0,0.8893 -0.64984,1.5392 -0.64984,0.6499 -1.53908,0.6499 l -83.180612,0 q -0.889337,0 -1.539177,-0.6499 -0.64984,-0.6499 -0.64984,-1.5392 l 0,-13.1337 q 0,-0.9577 0.615652,-1.5734 0.615653,-0.6156 1.573365,-0.6156 l 83.180612,0 q 0.88924,0 1.53908,0.6498 0.64984,0.6499 0.64984,1.5392 z"
style="fill:url(#linearGradient850);fill-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4141"
d="m 124.77795,981.48749 0,13.13382 q 0,0.88924 -0.64984,1.53908 -0.64984,0.64984 -1.53908,0.64984 l -83.180612,0 q -0.889337,0 -1.539177,-0.64984 -0.64984,-0.64984 -0.64984,-1.53908 l 0,-13.13382 q 0,-0.95772 0.615652,-1.57337 0.615653,-0.61556 1.573365,-0.61556 l 83.180612,0 q 0.88924,0 1.53908,0.64984 0.64984,0.64984 0.64984,1.53909 z"
style="fill:url(#linearGradient850);fill-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4"
d="m 124.77795,946.46405 0,13.13382 q 0,0.88925 -0.64984,1.53909 -0.64984,0.64984 -1.53908,0.64984 l -83.180612,0 q -0.889337,0 -1.539177,-0.64984 -0.64984,-0.64984 -0.64984,-1.53909 l 0,-13.13382 q 0,-0.88925 0.64984,-1.53909 0.64984,-0.64984 1.539177,-0.64984 l 83.180612,0 q 0.88924,0 1.53908,0.64984 0.64984,0.64984 0.64984,1.53909 z"
style="fill:url(#linearGradient850);fill-opacity:1"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient850);fill-opacity:1"
d="m 124.77795,946.46405 0,13.13382 q 0,0.88925 -0.64984,1.53909 -0.64984,0.64984 -1.53908,0.64984 l -83.180612,0 q -0.889337,0 -1.539177,-0.64984 -0.64984,-0.64984 -0.64984,-1.53909 l 0,-13.13382 q 0,-0.88925 0.64984,-1.53909 0.64984,-0.64984 1.539177,-0.64984 l 83.180612,0 q 0.88924,0 1.53908,0.64984 0.64984,0.64984 0.64984,1.53909 z"
id="path4150"
inkscape:connector-curvature="0" />
<path
id="path4154"
d="m 124.77795,946.46405 0,13.13382 q 0,0.88925 -0.64984,1.53909 -0.64984,0.64984 -1.53908,0.64984 l -83.180612,0 q -0.889337,0 -1.539177,-0.64984 -0.64984,-0.64984 -0.64984,-1.53909 l 0,-13.13382 q 0,-0.88925 0.64984,-1.53909 0.64984,-0.64984 1.539177,-0.64984 l 83.180612,0 q 0.88924,0 1.53908,0.64984 0.64984,0.64984 0.64984,1.53909 z"
style="fill:url(#linearGradient850);fill-opacity:1"
inkscape:connector-curvature="0" />
</g>
<g
id="g831"
style="fill:#2caf45;fill-opacity:1">
<circle
r="11.092738"
cy="953.03094"
cx="16.484426"
id="path4148"
style="fill:#2caf45;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
style="fill:#2caf45;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle4152"
cx="16.484426"
cy="988.05438"
r="11.092738" />
<circle
r="11.092738"
cy="1023.0778"
cx="16.484426"
id="circle4156"
style="fill:#2caf45;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-text-bold.svg">
<defs
id="defs4">
@ -23,11 +23,11 @@
inkscape:collect="always"
id="linearGradient4235">
<stop
style="stop-color:#0d5cc6;stop-opacity:1;"
style="stop-color:#b2cffa;stop-opacity:1"
offset="0"
id="stop4237" />
<stop
style="stop-color:#020e1e;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="1"
id="stop4239" />
</linearGradient>
@ -50,17 +50,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.999999"
inkscape:zoom="5.6568539"
inkscape:cx="29.797726"
inkscape:cy="52.767291"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0"
showguides="false" />
<metadata

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-text-color.svg">
<defs
id="defs4" />
@ -25,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="53.188911"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -93,7 +93,7 @@
transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,0,0)"
y="732.13635"
x="-634.40143"
style="fill:#0a50a9;fill-opacity:1" />
style="fill:#2271d5;fill-opacity:1" />
<polygon
id="polygon8"
points="19.092,13.435 18.385,12.728 13.435,7.778 12.727,7.071 10.605,9.192 16.971,15.557 "

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-text-heading.svg">
<defs
id="defs4">
@ -23,11 +23,11 @@
inkscape:collect="always"
id="linearGradient4139">
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
style="stop-color:#b2cffa;stop-opacity:1"
offset="0"
id="stop4141" />
<stop
style="stop-color:#020e1e;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="1"
id="stop4143" />
</linearGradient>
@ -50,17 +50,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:zoom="7.919596"
inkscape:cx="61.892855"
inkscape:cy="54.756941"
inkscape:cy="82.536136"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.92.1 r"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-text-hr.svg">
<defs
id="defs4" />
@ -26,16 +26,16 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:cx="50.735407"
inkscape:cx="34.76237"
inkscape:cy="62.616635"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -89,7 +89,7 @@
<path
d="m 127,990.98716 v -5.25 q 0,-1.1484 -0.73828,-1.8867 -0.73828,-0.7383 -1.88672,-0.7383 H 3.6250002 q -1.14844,0 -1.88672,0.7383 -0.7382799,0.7383 -0.7382799,1.8867 v 5.25 q 0,1.1484 0.7382799,1.8867 0.73828,0.7383 1.88672,0.7383 H 124.375 q 1.14844,0 1.88672,-0.7383 Q 127,992.13556 127,990.98716 Z"
id="path4"
style="fill:#0d5cc6;fill-opacity:1"
style="fill:#2caf45;fill-opacity:1"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-text-italic.svg">
<defs
id="defs4">
@ -23,11 +23,11 @@
inkscape:collect="always"
id="linearGradient4139">
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
style="stop-color:#b2cffa;stop-opacity:1"
offset="0"
id="stop4141" />
<stop
style="stop-color:#020e1e;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="1"
id="stop4143" />
</linearGradient>
@ -50,17 +50,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:zoom="5.6"
inkscape:cx="43.191939"
inkscape:cy="49.735915"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -7,7 +7,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
@ -15,56 +14,10 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-text-strikethrough.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4149">
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
offset="0"
id="stop4151" />
<stop
style="stop-color:#020e1e;stop-opacity:1"
offset="1"
id="stop4153" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4149"
id="radialGradient4155"
cx="64"
cy="988.36218"
fx="64"
fy="988.36218"
r="36"
gradientTransform="matrix(1,0,0,1.5000006,0,-494.18164)"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4149"
id="radialGradient4152"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,1.5000006,0,-494.18164)"
cx="64"
cy="988.36218"
fx="64"
fy="988.36218"
r="36" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4149"
id="radialGradient4154"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,1.5000006,0,-494.18164)"
cx="64"
cy="988.36218"
fx="64"
fy="988.36218"
r="36" />
</defs>
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -72,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:zoom="7.919596"
inkscape:cx="52.937487"
inkscape:cy="73.610886"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -133,28 +86,20 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36216)">
<g
id="g4145"
transform="matrix(1,0,0,1.0251369,0,-31.378774)">
<path
style="fill:#0d5cc6;fill-opacity:1"
id="path4143"
d="m 124.75,988.36216 q 0.98438,0 1.61719,0.6328 0.63281,0.6328 0.63281,1.6172 l 0,4.5 q 0,0.9844 -0.63281,1.6172 -0.63281,0.6328 -1.61719,0.6328 l -121.5,0 q -0.98437,0 -1.61719,-0.6328 Q 1,996.09656 1,995.11216 l 0,-4.5 q 0,-0.9844 0.63281,-1.6172 0.63282,-0.6328 1.61719,-0.6328 l 121.5,0 z"
inkscape:connector-curvature="0" />
<g
style="fill:url(#radialGradient4155);fill-opacity:1"
id="g4148">
<path
style="fill:url(#radialGradient4152);fill-opacity:1"
d="m 34.96094,983.86216 q -1.96875,-2.4609 -3.58594,-5.625 Q 28,971.41686 28,965.01846 q 0,-12.7266 9.42188,-21.7266 9.35156,-8.9297 27.63281,-8.9297 3.51562,0 11.74219,1.3359 4.64062,0.8438 12.44531,3.375 0.70312,2.6719 1.47656,8.2969 0.98438,8.6485 0.98438,12.8672 0,1.2656 -0.35157,3.1641 l -0.84375,0.2109 -5.90625,-0.4219 -0.98437,-0.1406 q -3.51563,-10.4766 -7.24219,-14.4141 -6.1875,-6.3984 -14.76562,-6.3984 -8.01563,0 -12.79688,4.1484 -4.71094,4.0782 -4.71094,10.2657 0,5.1328 4.64063,9.8437 4.64062,4.711 19.61719,9.0703 4.85156,1.4063 12.16406,4.6407 4.07812,1.9687 6.67969,3.6562 l -52.24219,0 z"
id="path4141"
inkscape:connector-curvature="0" />
<path
style="fill:url(#radialGradient4154);fill-opacity:1"
d="m 70.60938,1001.8622 28.89843,0 Q 100,1004.6044 100,1008.331 q 0,7.8046 -2.88281,14.9062 -1.61719,3.8672 -4.99219,7.3125 -2.60156,2.4609 -7.66406,5.6953 -5.625,3.375 -10.75781,4.6406 -5.625,1.4766 -14.27344,1.4766 -8.01563,0 -13.71094,-1.6172 l -9.84375,-2.8125 q -4.00781,-1.125 -5.0625,-1.9687 -0.5625,-0.5625 -0.5625,-1.5469 l 0,-0.9141 q 0,-7.5937 -0.14062,-10.9687 -0.0703,-2.1094 0,-4.7813 l 0.14062,-2.6015 0,-3.0938 7.17188,-0.1406 q 1.05468,2.3906 2.10937,4.9922 1.05469,2.6015 1.58203,3.9375 0.52735,1.3359 0.87891,1.8984 2.46094,4.0078 5.625,6.6094 3.02344,2.5312 7.38281,4.0078 4.14844,1.5469 9.28125,1.5469 4.5,0 9.77344,-1.8985 5.41406,-1.8281 8.57812,-6.0468 3.30469,-4.2891 3.30469,-9.0703 0,-5.9063 -5.69531,-11.0391 -2.39063,-2.0391 -9.63281,-4.9922 z"
id="path4"
inkscape:connector-curvature="0" />
</g>
</g>
<path
inkscape:connector-curvature="0"
d="m 124.75,981.82775 q 0.98438,0 1.61719,0.6487 Q 127,983.12516 127,984.1343 v 4.61312 q 0,1.00915 -0.63281,1.65785 -0.63281,0.64871 -1.61719,0.64871 H 3.25 q -0.98437,0 -1.61719,-0.64871 Q 1,989.75657 1,988.74742 v -4.61312 q 0,-1.00914 0.63281,-1.65785 0.63282,-0.6487 1.61719,-0.6487 z"
id="path4143"
style="fill:#2caf45;fill-opacity:1;stroke-width:1.01249039" />
<path
style="fill:#2271d5;fill-opacity:1;stroke-width:1.01249039"
d="M 34.96094,977.21463 Q 32.99219,974.69187 31.375,971.44824 28,964.45649 28,957.89726 q 0,-13.04651 9.42188,-22.27274 9.35156,-9.15417 27.63281,-9.15417 3.51562,0 11.74219,1.36948 4.64062,0.86502 12.44531,3.45984 0.70312,2.73906 1.47656,8.50546 0.98438,8.8659 0.98438,13.19064 0,1.29741 -0.35157,3.24364 l -0.84375,0.2162 -5.90625,-0.43251 -0.98437,-0.14413 q -3.51563,-10.73995 -7.24219,-14.77643 -6.1875,-6.55923 -14.76562,-6.55923 -8.01563,0 -12.79688,4.25268 -4.71094,4.18071 -4.71094,10.52374 0,5.26183 4.64063,10.09114 4.64062,4.82942 19.61719,9.2983 4.85156,1.44165 12.16406,4.75736 4.07812,2.01818 6.67969,3.7481 z"
id="path4141"
inkscape:connector-curvature="0" />
<path
style="fill:#2271d5;fill-opacity:1;stroke-width:1.01249039"
d="M 70.60938,995.66714 H 99.50781 Q 100,998.47827 100,1002.2985 q 0,8.0008 -2.88281,15.2809 -1.61719,3.9644 -4.99219,7.4964 -2.60156,2.5227 -7.66406,5.8384 -5.625,3.4598 -10.75781,4.7573 -5.625,1.5137 -14.27344,1.5137 -8.01563,0 -13.71094,-1.6579 l -9.84375,-2.8832 q -4.00781,-1.1532 -5.0625,-2.0182 -0.5625,-0.5766 -0.5625,-1.5857 v -0.9371 q 0,-7.7846 -0.14062,-11.2444 -0.0703,-2.1625 0,-4.9015 l 0.14062,-2.6669 v -3.1716 l 7.17188,-0.1441 q 1.05468,2.4507 2.10937,5.1177 1.05469,2.6669 1.58203,4.0364 0.52735,1.3695 0.87891,1.9462 2.46094,4.1085 5.625,6.7755 3.02344,2.5948 7.38281,4.1085 4.14844,1.5858 9.28125,1.5858 4.5,0 9.77344,-1.9462 5.41406,-1.874 8.57812,-6.1988 3.30469,-4.3969 3.30469,-9.2983 0,-6.0548 -5.69531,-11.3166 -2.39063,-2.09033 -9.63281,-5.11766 z"
id="path4"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-text-subscript.svg">
<defs
id="defs4" />
@ -25,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:zoom="5.6"
inkscape:cx="61.234372"
inkscape:cy="36.681475"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -89,12 +89,12 @@
<path
d="m 76.984807,1022.7464 0,13.7439 -20.41019,0 -13.08556,-20.7394 -1.97518,-3.4565 q -0.65839,-0.7407 -0.90529,-1.7283 l -0.2469,0 -0.74069,1.7283 q -0.82299,1.646 -2.05748,3.621 l -12.75637,20.5749 -21.2331803,0 0,-13.7439 10.5342903,0 16.21293,-23.94897 -15.22534,-22.3855 -11.2749803,0 0,-13.82615 22.7145603,0 11.43959,18.76415 q 0.16459,0.3292 1.89288,3.4566 0.65839,0.7406 0.90529,1.7282 l 0.24689,0 q 0.2469,-0.7407 0.90529,-1.7282 l 2.05748,-3.4566 11.52188,-18.76415 21.15089,0 0,13.82615 -10.2874,0 -15.14304,21.9739 16.78903,24.36057 8.9706,0 z"
id="path4141"
style="fill:#05244e;fill-opacity:1"
style="fill:#2271d5;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
d="m 126.43179,1035.247 0,16.9536 -42.301761,0 -0.3292,-2.2221 q -0.2469,-3.7034 -0.2469,-3.7857 0,-5.2672 2.13978,-9.629 2.13978,-4.3619 5.34945,-7.1189 3.20966,-2.757 6.91312,-5.3495 3.703471,-2.5924 6.913131,-4.4853 3.20967,-1.8928 5.34945,-4.4441 2.13978,-2.5513 2.13978,-5.2672 0,-3.1273 -2.42783,-5.1437 -2.42782,-2.0163 -5.80209,-2.0163 -4.197261,0 -7.983021,3.2097 -1.15219,0.9053 -2.96277,3.1273 l -8.64141,-7.5715 q 2.13978,-3.045 5.18485,-5.4317 6.58393,-5.3495 15.472241,-5.3495 9.05291,0 14.64925,4.8968 5.59634,4.8968 5.59634,13.0444 0,5.4318 -2.83932,9.7525 -2.83932,4.3207 -6.91313,7.0777 -4.07381,2.757 -8.18876,5.1437 -4.11496,2.3867 -7.16003,5.1849 -3.045071,2.7981 -3.374271,6.0078 l 19.093411,0 0,-6.5839 10.36969,0 z"
id="path4"
style="fill:#0d5cc6;fill-opacity:1"
style="fill:#2caf45;fill-opacity:1"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -89,12 +89,12 @@
<path
d="m 75.420992,1023.2866 0,13.7439 -20.41019,0 -13.08556,-20.7394 -1.97518,-3.4565 q -0.65839,-0.7407 -0.90529,-1.7283 l -0.2469,0 -0.74069,1.7283 q -0.82299,1.646 -2.05748,3.6211 l -12.75637,20.5748 -21.2331795,0 0,-13.7439 10.5342895,0 16.21293,-23.94913 -15.22534,-22.38539 -11.2749795,0 0,-13.8262 22.7145595,0 11.43959,18.7642 q 0.16459,0.3292 1.89288,3.4566 0.65839,0.7406 0.90529,1.7282 l 0.24689,0 q 0.2469,-0.7407 0.90529,-1.7282 l 2.05748,-3.4566 11.52188,-18.7642 21.15089,0 0,13.8262 -10.2874,0 -15.14304,21.97389 16.78903,24.36063 8.9706,0 z"
id="path4141"
style="fill:#05244e;fill-opacity:1"
style="fill:#2271d5;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
d="m 126.68433,971.96849 0,16.9536 -42.301763,0 -0.3292,-2.2221 q -0.2469,-3.7034 -0.2469,-3.7857 0,-5.2672 2.13978,-9.629 2.13978,-4.3619 5.34945,-7.1189 3.20966,-2.757 6.91312,-5.3495 3.703473,-2.5924 6.913133,-4.4853 3.20967,-1.8928 5.34945,-4.44414 2.13978,-2.5513 2.13978,-5.2672 0,-3.1273 -2.42783,-5.1437 -2.42782,-2.0163 -5.80209,-2.0163 -4.19726,0 -7.983023,3.2097 -1.15219,0.9053 -2.96277,3.1273 l -8.64141,-7.5715 q 2.13978,-3.045 5.18485,-5.4317 6.58393,-5.3495 15.472243,-5.3495 9.05291,0 14.64925,4.8968 5.59634,4.8968 5.59634,13.0444 0,5.4318 -2.83932,9.75254 -2.83932,4.3207 -6.91313,7.0777 -4.07381,2.757 -8.18876,5.1437 -4.11496,2.3867 -7.16003,5.1849 -3.045073,2.7981 -3.374273,6.0078 l 19.093413,0 0,-6.5839 10.36969,0 z"
id="path4"
style="fill:#0d5cc6;fill-opacity:1"
style="fill:#2caf45;fill-opacity:1"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -14,7 +14,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="format-text-underline.svg">
<defs
id="defs4" />
@ -25,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:zoom="5.6"
inkscape:cx="50.735407"
inkscape:cy="44.938966"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -89,12 +89,12 @@
<path
d="m 4.9375164,939.15294 q -3.03516,-0.1641 -3.69141,-0.3282 l -0.24609,-7.2187 q 1.06641,-0.082 3.28125,-0.082 4.92188,0 9.1875006,0.3281 10.82813,0.5742 13.61719,0.5742 7.05469,0 13.78125,-0.2461 9.51562,-0.3281 11.97656,-0.4102 4.59375,0 7.05469,-0.164 l -0.082,1.1484 0.16406,5.25 0,0.7383 q -4.92188,0.7383 -10.17188,0.7383 -4.92187,0 -6.48046,2.0508 -1.06641,1.1484 -1.06641,10.8281 0,1.0664 0.041,2.666 0.041,1.5996 0.041,2.0918 l 0.082,18.7852 1.14844,22.9687 q 0.49219,10.17196 4.18359,16.57036 2.8711,4.8399 7.875,7.5469 7.21875,3.8555 14.51953,3.8555 8.53125,0 15.66797,-2.2969 4.59375,-1.4766 8.1211,-4.1836 3.9375,-2.9531 5.33203,-5.25 2.953113,-4.5937 4.347643,-9.3517 1.72266,-5.98816 1.72266,-18.78506 0,-6.4805 -0.28711,-10.5 -0.28711,-4.0195 -0.90234,-10.0488 -0.61524,-6.0293 -1.10742,-13.084 l -0.32813,-4.8399 q -0.41016,-5.4961 -1.96875,-7.2187 -2.789053,-2.8711 -6.316403,-2.7891 l -8.20312,0.1641 -1.14844,-0.2461 0.16406,-7.0547 6.89063,0 16.816403,0.8203 q 6.23437,0.2461 16.07812,-0.8203 l 1.47656,0.1641 q 0.49219,3.1171 0.49219,4.1835 0,0.5743 -0.32812,2.543 -3.69141,0.9844 -6.89063,1.0664 -5.98828,0.9024 -6.48047,1.3946 -1.23047,1.2304 -1.23047,3.3632 0,0.5743 0.12305,2.2149 0.12305,1.6406 0.12305,2.543 0.65625,1.5585 1.80468,32.4843 0.49219,15.9961 -1.23046,24.93756 -1.23047,6.2344 -3.36329,10.0078 -3.11718,5.3321 -9.18749,10.0899 -6.152343,4.6758 -14.929683,7.3008 -8.94141,2.707 -20.91797,2.707 -13.69922,0 -23.29688,-3.7734 -9.76172,-3.8555 -14.68359,-10.0078 -5.00391,-6.2344 -6.80859,-15.9961 -1.3125,-6.5626 -1.3125,-19.44156 l 0,-27.3164 q 0,-15.4218 -1.39454,-17.4726 -2.05078,-2.9531 -12.0585906,-3.1992 z"
id="path4141"
style="fill:#052147;fill-opacity:1"
style="fill:#2271d5;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
d="m 127,1049.5579 0,-5.25 q 0,-1.1484 -0.73828,-1.8867 -0.73828,-0.7383 -1.88672,-0.7383 l -120.7499996,0 q -1.14844,0 -1.88672,0.7383 -0.7382799,0.7383 -0.7382799,1.8867 l 0,5.25 q 0,1.1484 0.7382799,1.8867 0.73828,0.7383 1.88672,0.7383 l 120.7499996,0 q 1.14844,0 1.88672,-0.7383 Q 127,1050.7063 127,1049.5579 Z"
id="path4"
style="fill:#0d5cc6;fill-opacity:1"
style="fill:#2caf45;fill-opacity:1"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -2,9 +2,8 @@
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import (unicode_literals, division, absolute_import,
print_function)
import os, glob, subprocess, argparse
from __future__ import absolute_import, division, print_function, unicode_literals
import os, glob, subprocess, argparse, json, hashlib
duplicates = {
'character-set': ['languages'],
@ -27,6 +26,13 @@ skip = {'calibre'}
j = os.path.join
base = os.path.dirname(os.path.abspath(__file__))
output_base = j(os.path.dirname(base), 'resources', 'images')
hash_path = j(os.path.dirname(base), '.build-cache', 'imgsrc-gen.json')
if os.path.exists(hash_path):
with open(hash_path, 'rb') as f:
hashes = json.load(f)
else:
hashes = {}
src_hashes = {}
def iterfiles(only=()):
@ -34,6 +40,9 @@ def iterfiles(only=()):
name = os.path.relpath(src, base).rpartition('.')[0]
if only and name not in only:
continue
src_hashes[name] = h = hashlib.sha1(open(src, 'rb').read()).hexdigest()
if not only and h == hashes.get(name):
continue
output_names = [n for n in [name] + duplicates.get(name, []) if n not in skip]
output_files = [j(output_base, n) + '.png' for n in output_names]
if output_files:
@ -54,6 +63,8 @@ def render(src, output_files):
size = sizes.get(oname, '128')
print('Rendering', oname, 'at size:', size)
rsvg(src, size, dest)
name = os.path.relpath(src, base).rpartition('.')[0]
hashes[name] = src_hashes[name]
def main():
@ -62,6 +73,8 @@ def main():
args = p.parse_args()
for src, ofiles in iterfiles(args.only):
render(src, ofiles)
with open(hash_path, 'w') as f:
json.dump(hashes, f, indent=2, sort_keys=True)
if __name__ == '__main__':

111
imgsrc/generic-library.svg Normal file
View File

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
fill="#000000"
viewBox="0 0 17 17"
version="1.1"
x="0px"
y="0px"
id="svg18"
sodipodi:docname="generic-library.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14">
<metadata
id="metadata24">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs22">
<linearGradient
inkscape:collect="always"
id="linearGradient848">
<stop
style="stop-color:#0b59bd;stop-opacity:1"
offset="0"
id="stop844" />
<stop
style="stop-color:#b2cffa;stop-opacity:1"
offset="1"
id="stop846" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient848"
id="linearGradient850"
x1="8.8487625"
y1="17.227978"
x2="8.4970684"
y2="-0.060158744"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1400"
id="namedview20"
showgrid="false"
inkscape:zoom="55.529412"
inkscape:cx="6.6271186"
inkscape:cy="8.5"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="0"
inkscape:current-layer="svg18" />
<g
id="g842"
style="fill-opacity:1;fill:url(#linearGradient850)">
<path
id="path2"
d="M1.7866,6.5 L15.9196,6.5 C16.8236,6.5 17.1906,5.336 16.4496,4.818 L11.5146,1.363 C9.9166,0.244 7.7896,0.244 6.1916,1.363 L1.2566,4.818 C0.5156,5.336 0.8826,6.5 1.7866,6.5"
style="fill-opacity:1;fill:url(#linearGradient850)" />
<polygon
id="polygon4"
points="1.853 12.5 3.853 12.5 3.853 7.5 1.853 7.5"
style="fill-opacity:1;fill:url(#linearGradient850)" />
<polygon
id="polygon6"
points="4.853 12.5 6.853 12.5 6.853 7.5 4.853 7.5"
style="fill-opacity:1;fill:url(#linearGradient850)" />
<polygon
id="polygon8"
points="7.853 12.5 9.853 12.5 9.853 7.5 7.853 7.5"
style="fill-opacity:1;fill:url(#linearGradient850)" />
<polygon
id="polygon10"
points="10.853 12.5 12.853 12.5 12.853 7.5 10.853 7.5"
style="fill-opacity:1;fill:url(#linearGradient850)" />
<polygon
id="polygon12"
points="13.853 12.5 15.853 12.5 15.853 7.5 13.853 7.5"
style="fill-opacity:1;fill:url(#linearGradient850)" />
<polygon
id="polygon14"
points="0.853 16.5 16.853 16.5 16.853 15.5 0.853 15.5"
style="fill-opacity:1;fill:url(#linearGradient850)" />
<polygon
id="polygon16"
points="1.853 14.5 15.853 14.5 15.853 13.5 1.853 13.5"
style="fill-opacity:1;fill:url(#linearGradient850)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="grid.svg">
<defs
id="defs4">
@ -23,11 +23,11 @@
inkscape:collect="always"
id="linearGradient4134">
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
style="stop-color:#b2cffa;stop-opacity:1"
offset="0"
id="stop4136" />
<stop
style="stop-color:#020e1e;stop-opacity:1"
style="stop-color:#0b59bd;stop-opacity:1"
offset="1"
id="stop4138" />
</linearGradient>
@ -50,17 +50,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="49.38296"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

113
imgsrc/h-ellipsis.svg Normal file
View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="h-ellipsis.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.656854"
inkscape:cx="4.4025571"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:creator>
<cc:Agent>
<dc:title>Kovid Goyal</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:rights>
<dc:publisher>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:publisher>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36216)">
<g
id="g831"
style="fill:#7d7d7d;fill-opacity:1"
transform="rotate(90,22.052892,1030.5691)">
<circle
r="11.092738"
cy="953.03094"
cx="16.484426"
id="path4148"
style="fill:#7d7d7d;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
style="fill:#7d7d7d;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle4152"
cx="16.484426"
cy="988.05438"
r="11.092738" />
<circle
r="11.092738"
cy="1023.0778"
cx="16.484426"
id="circle4156"
style="fill:#7d7d7d;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="heuristics.svg">
<defs
id="defs4">
@ -50,17 +50,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="33.653639"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -120,11 +120,11 @@
<g
transform="matrix(1.3939367,0,0,1.3695651,-5.6968353,-384.43812)"
id="g4"
style="fill:#3027dd;fill-opacity:1">
style="fill:#2271d5;fill-opacity:1">
<path
inkscape:connector-curvature="0"
d="m 20.000054,956.3622 c -1.94862,0.01 -3.01295,1.69 -3,3 l 0,86 c 1.6e-4,1.5708 1.42925,2.9998 3,3 l 60,0 c 1.57075,-2e-4 2.99984,-1.4292 3,-3 l 0,-70 c 0.002,-0.7861 -0.32012,-1.5681 -0.875,-2.125 l -16,-16 c -0.55685,-0.5549 -1.33889,-0.8769 -2.125,-0.875 l -44,0 z m 3,6 38,0 0,13 a 3.0003,3.0003 0 0 0 3,3 l 13,0 0,64 -54,0 0,-80 z m 44,4.2188 5.78125,5.7812 -5.78125,0 0,-5.7812 z"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#3027dd;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
style="color:#000000;text-indent:0;text-transform:none;direction:ltr;block-progression:tb;baseline-shift:baseline;display:inline;overflow:visible;visibility:visible;fill:#2271d5;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
visibility="visible"
display="inline"
overflow="visible"

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -7,7 +7,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
@ -15,57 +14,10 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="highlight_only_off.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4139">
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
offset="0"
id="stop4141" />
<stop
id="stop4147"
offset="0.51573128"
style="stop-color:#062a5a;stop-opacity:1" />
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
offset="1"
id="stop4143" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4139"
id="linearGradient4145"
x1="1"
y1="988.36218"
x2="127"
y2="988.36218"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,-2.1428647)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4139"
id="linearGradient4149"
gradientUnits="userSpaceOnUse"
x1="1"
y1="988.36218"
x2="127"
y2="988.36218"
gradientTransform="translate(0,12.946445)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4139"
id="linearGradient4151"
gradientUnits="userSpaceOnUse"
x1="1"
y1="988.36218"
x2="127"
y2="988.36218"
gradientTransform="translate(-6.85e-7,28.035712)" />
</defs>
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -73,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="38.236962"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -134,21 +86,25 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36216)">
<path
style="fill:url(#linearGradient4151);fill-opacity:1"
d="m 127,1025.3979 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117.0000007,0 q -1.82812,0 -3.16406,-1.3359 -1.33594003,-1.336 -1.33594003,-3.1641 l 0,-9 q 0,-1.8281 1.33594003,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117.0000007,0 q 1.82813,0 3.16406,1.3359 1.33594,1.336 1.33594,3.1641 z"
id="path4143"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient4149);fill-opacity:1"
d="m 127,983.3086 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117,0 q -1.82812,0 -3.16406,-1.3359 Q 1,994.1367 1,992.3086 l 0,-9 q 0,-1.8281 1.33594,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117,0 q 1.82813,0 3.16406,1.3359 Q 127,981.4805 127,983.3086 Z"
id="path4141"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient4145);fill-opacity:1"
d="m 127,941.21929 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117,0 q -1.82812,0 -3.16406,-1.3359 Q 1,952.04739 1,950.21929 l 0,-9 q 0,-1.8281 1.33594,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117,0 q 1.82813,0 3.16406,1.3359 1.33594,1.336 1.33594,3.1641 z"
id="path4"
inkscape:connector-curvature="0" />
<g
id="g826"
style="fill:#2271d5;fill-opacity:1">
<path
inkscape:connector-curvature="0"
id="path4143"
d="m 127,1025.3979 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117.0000007,0 q -1.82812,0 -3.16406,-1.3359 -1.33594003,-1.336 -1.33594003,-3.1641 l 0,-9 q 0,-1.8281 1.33594003,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117.0000007,0 q 1.82813,0 3.16406,1.3359 1.33594,1.336 1.33594,3.1641 z"
style="fill:#2271d5;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4141"
d="m 127,983.3086 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117,0 q -1.82812,0 -3.16406,-1.3359 Q 1,994.1367 1,992.3086 l 0,-9 q 0,-1.8281 1.33594,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117,0 q 1.82813,0 3.16406,1.3359 Q 127,981.4805 127,983.3086 Z"
style="fill:#2271d5;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4"
d="m 127,941.21929 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117,0 q -1.82812,0 -3.16406,-1.3359 Q 1,952.04739 1,950.21929 l 0,-9 q 0,-1.8281 1.33594,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117,0 q 1.82813,0 3.16406,1.3359 1.33594,1.336 1.33594,3.1641 z"
style="fill:#2271d5;fill-opacity:1" />
</g>
<path
style="fill:#b60c09;fill-opacity:1"
d="m 125.33871,1041.5223 -8.17848,8.1786 q -1.66126,1.6613 -4.08931,1.6613 -2.42794,0 -4.08921,-1.6613 L 2.6612865,943.38045 q -1.6612525,-1.66124 -1.6612882,-4.08921 5.41e-5,-2.42804 1.6612882,-4.08929 l 8.1784945,-8.17849 q 1.661234,-1.66123 4.089285,-1.66129 2.427958,4e-5 4.089209,1.66129 L 125.33871,1033.3439 q 1.66126,1.6613 1.66129,4.0893 -6e-5,2.428 -1.66129,4.0891 z"

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -7,7 +7,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
@ -15,57 +14,10 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="highlight_only_on.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4139">
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
offset="0"
id="stop4141" />
<stop
id="stop4147"
offset="0.51573128"
style="stop-color:#062a5a;stop-opacity:1" />
<stop
style="stop-color:#0d5cc6;stop-opacity:1"
offset="1"
id="stop4143" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4139"
id="linearGradient4145"
x1="1"
y1="988.36218"
x2="127"
y2="988.36218"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,-2.1428647)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4139"
id="linearGradient4149"
gradientUnits="userSpaceOnUse"
x1="1"
y1="988.36218"
x2="127"
y2="988.36218"
gradientTransform="translate(0,12.946445)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4139"
id="linearGradient4151"
gradientUnits="userSpaceOnUse"
x1="1"
y1="988.36218"
x2="127"
y2="988.36218"
gradientTransform="translate(-6.85e-7,28.035712)" />
</defs>
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -73,17 +25,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="7.9691049"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -134,20 +86,24 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36216)">
<path
style="fill:url(#linearGradient4151);fill-opacity:1"
d="m 127,1025.3979 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117.0000007,0 q -1.82812,0 -3.16406,-1.3359 -1.33594003,-1.336 -1.33594003,-3.1641 l 0,-9 q 0,-1.8281 1.33594003,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117.0000007,0 q 1.82813,0 3.16406,1.3359 1.33594,1.336 1.33594,3.1641 z"
id="path4143"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient4149);fill-opacity:1"
d="m 127,983.3086 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117,0 q -1.82812,0 -3.16406,-1.3359 Q 1,994.1367 1,992.3086 l 0,-9 q 0,-1.8281 1.33594,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117,0 q 1.82813,0 3.16406,1.3359 Q 127,981.4805 127,983.3086 Z"
id="path4141"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient4145);fill-opacity:1"
d="m 127,941.21929 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117,0 q -1.82812,0 -3.16406,-1.3359 Q 1,952.04739 1,950.21929 l 0,-9 q 0,-1.8281 1.33594,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117,0 q 1.82813,0 3.16406,1.3359 1.33594,1.336 1.33594,3.1641 z"
id="path4"
inkscape:connector-curvature="0" />
<g
id="g828"
style="fill:#2271d5;fill-opacity:1">
<path
inkscape:connector-curvature="0"
id="path4143"
d="m 127,1025.3979 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117.0000007,0 q -1.82812,0 -3.16406,-1.3359 -1.33594003,-1.336 -1.33594003,-3.1641 l 0,-9 q 0,-1.8281 1.33594003,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117.0000007,0 q 1.82813,0 3.16406,1.3359 1.33594,1.336 1.33594,3.1641 z"
style="fill:#2271d5;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4141"
d="m 127,983.3086 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117,0 q -1.82812,0 -3.16406,-1.3359 Q 1,994.1367 1,992.3086 l 0,-9 q 0,-1.8281 1.33594,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117,0 q 1.82813,0 3.16406,1.3359 Q 127,981.4805 127,983.3086 Z"
style="fill:#2271d5;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4"
d="m 127,941.21929 0,9 q 0,1.8281 -1.33594,3.1641 -1.33593,1.3359 -3.16406,1.3359 l -117,0 q -1.82812,0 -3.16406,-1.3359 Q 1,952.04739 1,950.21929 l 0,-9 q 0,-1.8281 1.33594,-3.1641 1.33594,-1.3359 3.16406,-1.3359 l 117,0 q 1.82813,0 3.16406,1.3359 1.33594,1.336 1.33594,3.1641 z"
style="fill:#2271d5;fill-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -15,8 +15,9 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="html-fix.svg">
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="html-fix.svg"
enable-background="new">
<defs
id="defs4">
<linearGradient
@ -104,6 +105,16 @@
result="composite2"
id="feComposite4467" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter871">
<feBlend
inkscape:collect="always"
mode="overlay"
in2="BackgroundImage"
id="feBlend873" />
</filter>
</defs>
<sodipodi:namedview
id="base"
@ -112,17 +123,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="5.6"
inkscape:cx="-10.424833"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -195,15 +206,15 @@
id="polyline14" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:45px;line-height:125%;font-family:Consolas;-inkscape-font-specification:Consolas;letter-spacing:0px;word-spacing:0px;fill:#6d0b0b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4457)"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:Consolas;-inkscape-font-specification:Consolas;letter-spacing:0px;word-spacing:0px;fill:#dd8808;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter871);"
x="7.5610352"
y="1020.3086"
id="text4151"
sodipodi:linespacing="125%"><tspan
id="text4151"><tspan
sodipodi:role="line"
id="tspan4153"
x="7.5610352"
y="1020.3086">HTML</tspan></text>
y="1020.3086"
style="font-size:45px;line-height:1.25;fill:#dd8808;fill-opacity:1;">HTML</tspan></text>
<path
inkscape:connector-curvature="0"
d="m 62.500001,944.14932 q 0,1.11152 -0.778059,1.88963 l -20.11853,20.11853 -3.779167,3.7791 q -0.778072,0.77811 -1.889584,0.77811 -1.111526,0 -1.889598,-0.77811 l -3.779168,-3.7791 -10.059265,-10.05934 q -0.778058,-0.77797 -0.778058,-1.88948 0,-1.11152 0.778058,-1.88963 l 3.779182,-3.77911 q 0.778058,-0.77812 1.889584,-0.77812 1.111512,0 1.889584,0.77812 l 8.169681,8.19743 18.228932,-18.25677 q 0.778072,-0.77811 1.889584,-0.77811 1.111525,0 1.889584,0.77811 l 3.779181,3.77925 q 0.778059,0.77798 0.778059,1.88949 z"

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -15,7 +15,7 @@
viewBox="0 0 128 128"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="icon_choose.svg">
<defs
id="defs4" />
@ -26,17 +26,17 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:zoom="7.919596"
inkscape:cx="53.868545"
inkscape:cy="69.707741"
inkscape:document-units="px"
inkscape:current-layer="svg2"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2128"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-y="40"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
@ -87,32 +87,28 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36216)">
<g
id="g4149"
transform="matrix(0.88920982,0,0,0.90113892,-35.480349,84.31281)">
<path
style="overflow:visible;fill:#546e7a"
inkscape:connector-curvature="0"
id="path7"
d="m 173.86824,934.4279 -123.986482,0 c -4.890824,0 -8.856178,3.64373 -8.856178,8.13786 l 0,81.37854 c 0,4.4941 3.965354,8.1378 8.856178,8.1378 l 123.986482,0 c 4.89083,0 8.85618,-3.6437 8.85618,-8.1378 l 0,-81.37854 c 0,-4.49413 -3.96535,-8.13786 -8.85618,-8.13786 z m 0,89.5164 -123.986482,0 0,-81.37854 123.986482,0 0,81.37854 z" />
<path
style="overflow:visible;fill:#ffa000"
inkscape:connector-curvature="0"
id="path9"
d="m 76.450293,958.84147 c 4.89525,0 8.85617,3.63966 8.85617,8.13786 0,4.4982 -3.96092,8.13785 -8.85617,8.13785 -4.89525,0 -8.85618,-3.63965 -8.85618,-8.13785 0,-4.4982 3.96093,-8.13786 8.85618,-8.13786 m 0,-8.13786 c -9.76837,0 -17.71236,7.29966 -17.71236,16.27572 0,8.97605 7.94399,16.27571 17.71236,16.27571 9.76836,0 17.71235,-7.29966 17.71235,-16.27571 0,-8.97606 -7.94399,-16.27572 -17.71235,-16.27572 l 0,0 z" />
<path
style="overflow:visible;fill:#b0bec5"
inkscape:connector-curvature="0"
id="path11"
d="m 72.022203,1015.8064 c -1.13249,0 -2.26608,-0.3977 -3.13066,-1.1922 -1.73028,-1.5899 -1.73028,-4.1645 0,-5.7534 l 26.56853,-24.41356 c 1.35832,-1.24001 3.41627,-1.5462 5.111117,-0.76293 l 14.40901,6.62015 24.35006,-29.83338 c 0.85572,-1.05691 2.27493,-1.67335 3.66313,-1.62961 1.44024,0.0397 2.76756,0.71105 3.56351,1.81169 l 17.71235,24.41357 c 1.35832,1.87171 0.80813,4.39444 -1.22769,5.64259 -2.04135,1.23594 -4.79119,0.73953 -6.14065,-1.12811 l -14.24073,-19.62953 -22.81573,27.94947 c -1.27972,1.57773 -3.60668,2.08227 -5.52183,1.20033 l -14.858447,-6.82664 -24.31131,22.33936 c -0.86459,0.7945 -1.99818,1.1922 -3.13066,1.1922 z" />
</g>
<path
d="M 119.125,926.36216 H 8.8750001 c -4.3489688,0 -7.87500049,3.28351 -7.87500049,7.33334 v 73.3334 c 0,4.0498 3.52603169,7.3333 7.87500049,7.3333 H 119.125 c 4.34897,0 7.875,-3.2835 7.875,-7.3333 v -73.3334 c 0,-4.04983 -3.52603,-7.33334 -7.875,-7.33334 z m 0,80.66674 H 8.8750001 V 933.6955 H 119.125 Z"
id="path7"
inkscape:connector-curvature="0"
style="overflow:visible;fill:#2271d5;stroke-width:0.89515448;fill-opacity:1" />
<path
d="m 32.500002,948.36218 c 4.352905,0 7.874994,3.27984 7.874994,7.33334 0,4.0535 -3.522089,7.33333 -7.874994,7.33333 -4.352904,0 -7.875002,-3.27983 -7.875002,-7.33333 0,-4.0535 3.522098,-7.33334 7.875002,-7.33334 m 0,-7.33335 c -8.68613,0 -15.750004,6.57801 -15.750004,14.66669 0,8.08867 7.063874,14.66667 15.750004,14.66667 8.686122,0 15.749996,-6.578 15.749996,-14.66667 0,-8.08868 -7.063874,-14.66669 -15.749996,-14.66669 z"
id="path9"
inkscape:connector-curvature="0"
style="overflow:visible;fill:#ffa000;stroke-width:0.89515448" />
<path
d="m 28.562501,999.69549 c -1.007021,0 -2.01502,-0.35838 -2.783813,-1.07434 -1.538582,-1.43272 -1.538582,-3.75279 0,-5.18461 l 23.624997,-22.00001 c 1.207832,-1.11742 3.037781,-1.39334 4.544856,-0.6875 l 12.812633,5.96567 21.652312,-26.88402 c 0.760915,-0.95242 2.022891,-1.50792 3.257292,-1.4685 1.280675,0.0358 2.460941,0.64075 3.168708,1.63258 l 15.749994,22.00002 c 1.20783,1.68667 0.7186,3.96 -1.09167,5.08476 -1.81519,1.11375 -4.26038,0.66642 -5.46033,-1.01659 L 91.374484,958.37402 71.086513,983.56037 c -1.13794,1.42176 -3.207095,1.87642 -4.910066,1.08167 L 52.96417,978.49029 31.346315,998.62115 c -0.768802,0.71596 -1.776801,1.07434 -2.783814,1.07434 z"
id="path11"
inkscape:connector-curvature="0"
style="overflow:visible;fill:#b0bec5;stroke-width:0.89515448" />
</g>
<image
sodipodi:absref="/home/kovid/work/calibre/imgsrc/new/config.svg"
sodipodi:absref="/home/kovid/work/calibre/imgsrc/config.svg"
xlink:href="config.svg"
y="57.85714"
x="56.964283"
id="image7"
width="70.321426"
height="69.428574"
width="70.321426" />
id="image7"
x="56.964283"
y="57.85714" />
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Some files were not shown because too many files have changed in this diff Show More