Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add pdf thumbnail #6094

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/src/pages/lib-content-view/lib-content-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import cookie from 'react-cookies';
import moment from 'moment';
import { navigate } from '@gatsbyjs/reach-router';
import { gettext, siteRoot, username, enableVideoThumbnail } from '../../utils/constants';
import { gettext, siteRoot, username, enableVideoThumbnail, enablePDFThumbnail } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import collabServer from '../../utils/collab-server';
Expand Down Expand Up @@ -529,7 +529,7 @@ class LibContentView extends React.Component {

getThumbnails = (repoID, path, direntList) => {
let items = direntList.filter((item) => {
return (Utils.imageCheck(item.name) || (enableVideoThumbnail && Utils.videoCheck(item.name))) && !item.encoded_thumbnail_src;
return (Utils.imageCheck(item.name) || (enableVideoThumbnail && Utils.videoCheck(item.name)) || (enablePDFThumbnail && Utils.pdfCheck(item.name))) && !item.encoded_thumbnail_src;
});
if (items.length == 0) {
return ;
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/pages/starred/starred.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Link, navigate } from '@gatsbyjs/reach-router';
import moment from 'moment';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import { gettext, siteRoot, enableVideoThumbnail } from '../../utils/constants';
import { gettext, siteRoot, enableVideoThumbnail, enablePDFThumbnail } from '../../utils/constants';
import EmptyTip from '../../components/empty-tip';
import Loading from '../../components/loading';
import toaster from '../../components/toast';
Expand Down Expand Up @@ -79,7 +79,10 @@ class TableBody extends Component {

getThumbnails() {
let items = this.state.items.filter((item) => {
return (Utils.imageCheck(item.obj_name) || (enableVideoThumbnail && Utils.videoCheck(item.obj_name))) && !item.repo_encrypted && !item.encoded_thumbnail_src && !item.deleted;
return (Utils.imageCheck(item.obj_name) ||
(enableVideoThumbnail && Utils.videoCheck(item.obj_name)) ||
(enablePDFThumbnail && Utils.pdfCheck(item.obj_name))) &&
!item.repo_encrypted && !item.encoded_thumbnail_src && !item.deleted;
});
if (items.length == 0) {
return ;
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/shared-dir-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ let {
repoID, relativePath,
mode, thumbnailSize, zipped,
trafficOverLimit, canDownload,
noQuota, canUpload, enableVideoThumbnail
noQuota, canUpload, enableVideoThumbnail, enablePDFThumbnail
} = window.shared.pageOptions;

const showDownloadIcon = !trafficOverLimit && canDownload;
Expand Down Expand Up @@ -111,7 +111,8 @@ class SharedDirView extends React.Component {
let items = this.state.items.filter((item) => {
return !item.is_dir &&
(Utils.imageCheck(item.file_name) ||
(enableVideoThumbnail && Utils.videoCheck(item.file_name))) &&
(enableVideoThumbnail && Utils.videoCheck(item.file_name)) ||
(enablePDFThumbnail && Utils.pdfCheck(item.file_name))) &&
!item.encoded_thumbnail_src;
});
if (items.length == 0) {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export const curNoteID = window.app.pageOptions.curNoteID;
export const enableTC = window.app.pageOptions.enableTC;

export const enableVideoThumbnail = window.app.pageOptions.enableVideoThumbnail;
export const enablePDFThumbnail = window.app.pageOptions.enablePDFThumbnail;

export const enableOnlyoffice = window.app.pageOptions.enableOnlyoffice || false;
export const onlyofficeConverterExtensions = window.app.pageOptions.onlyofficeConverterExtensions || [];
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ export const Utils = {
}
},

pdfCheck: function(filename) {
if (filename.lastIndexOf('.') == -1) {
return false;
}
var file_ext = filename.substr(filename.lastIndexOf('.') + 1).toLowerCase();
var image_exts = ['pdf'];
if (image_exts.indexOf(file_ext) != -1) {
return true;
} else {
return false;
}
},

getShareLinkPermissionList: function(itemType, permission, path, canEdit) {
// itemType: library, dir, file
// permission: rw, r, admin, cloud-edit, preview, custom-*
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ Markdown==3.4.*
bleach==5.0.*
python-ldap==3.4.*
pypinyin==0.50.*
PyMuPDF==1.24.*
4 changes: 2 additions & 2 deletions seahub/api2/endpoints/dir.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
normalize_dir_path, is_pro_version, FILEEXT_TYPE_MAP, get_file_type_and_ext
from seahub.utils.timeutils import timestamp_to_isoformat_timestr
from seahub.utils.file_tags import get_files_tags_in_dir
from seahub.utils.file_types import IMAGE, VIDEO, XMIND, SEADOC
from seahub.utils.file_types import IMAGE, VIDEO, XMIND, SEADOC, PDF
from seahub.base.models import UserStarredFiles
from seahub.base.templatetags.seahub_tags import email2nickname, \
email2contact_email
Expand Down Expand Up @@ -175,7 +175,7 @@ def get_dir_file_info_list(username, request_type, repo_obj, parent_dir,
fileExt = os.path.splitext(file_name)[1][1:].lower()
file_type = FILEEXT_TYPE_MAP.get(fileExt)

if file_type in (IMAGE, XMIND) or \
if file_type in (IMAGE, XMIND, PDF) or \
(file_type == VIDEO and ENABLE_VIDEO_THUMBNAIL):

# if thumbnail has already been created, return its src.
Expand Down
3 changes: 3 additions & 0 deletions seahub/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,9 @@ def genpassword():
ENABLE_VIDEO_THUMBNAIL = False
THUMBNAIL_VIDEO_FRAME_TIME = 5 # use the frame at 5 second as thumbnail

# pdf thumbnails
ENABLE_PDF_THUMBNAIL = True

# template for create new office file
OFFICE_TEMPLATE_ROOT = os.path.join(MEDIA_ROOT, 'office-template')

Expand Down
1 change: 1 addition & 0 deletions seahub/templates/base_for_react.html
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
enableTC: {% if enable_terms_and_conditions %} true {% else %} false {% endif %},
enableSSOToThirdpartWebsite: {% if enable_sso_to_thirdpart_website %} true {% else %} false {% endif %},
enableVideoThumbnail: {% if enable_video_thumbnail %} true {% else %} false {% endif %},
enablePDFThumbnail: {% if enable_pdf_thumbnail %} true {% else %} false {% endif %},
showLogoutIcon: {% if show_logout_icon %} true {% else %} false {% endif %},
additionalShareDialogNote: {% if additional_share_dialog_note %} {{ additional_share_dialog_note|safe }} {% else %} null {% endif %},
additionalAppBottomLinks: {% if additional_app_bottom_links %} {{ additional_app_bottom_links|safe }} {% else %} null {% endif %},
Expand Down
4 changes: 4 additions & 0 deletions seahub/templates/common_file_view_react.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
enableVideoThumbnail: {% if enable_video_thumbnail %} true {% else %} false {% endif %},
{% endif %}

{% if filetype == 'PDF' %}
enablePDFThumbnail: {% if enable_pdf_thumbnail %} true {% else %} false {% endif %},
{% endif %}

{% if filetype == 'XMind' %}
xmindImageSrc: '{{ xmind_image_src|escapejs }}',
{% endif %}
Expand Down
1 change: 1 addition & 0 deletions seahub/templates/view_shared_dir_react.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
mode: '{{ mode }}',
thumbnailSize: {{ thumbnail_size }},
enableVideoThumbnail: {% if enable_video_thumbnail %}true{% else %}false{% endif %},
enablePDFThumbnail: {% if enable_pdf_thumbnail %}true{% else %}false{% endif %},
trafficOverLimit: {% if traffic_over_limit %}true{% else %}false{% endif %},
canDownload: {% if permissions.can_download %}true{% else %}false{% endif %},
noQuota: {% if no_quota %}true{% else %}false{% endif %},
Expand Down
43 changes: 41 additions & 2 deletions seahub/thumbnail/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import subprocess
from io import BytesIO
import zipfile
from fitz import open as fitz_open
try: # Py2 and Py3 compatibility
from urllib.request import urlretrieve
except:
Expand All @@ -18,7 +19,7 @@
seafile_api

from seahub.utils import gen_inner_file_get_url, get_file_type_and_ext
from seahub.utils.file_types import VIDEO, XMIND
from seahub.utils.file_types import VIDEO, XMIND, PDF
from seahub.settings import THUMBNAIL_IMAGE_SIZE_LIMIT, \
THUMBNAIL_EXTENSION, THUMBNAIL_ROOT, THUMBNAIL_IMAGE_ORIGINAL_SIZE_LIMIT,\
ENABLE_VIDEO_THUMBNAIL, THUMBNAIL_VIDEO_FRAME_TIME
Expand Down Expand Up @@ -117,7 +118,10 @@ def generate_thumbnail(request, repo_id, size, path):
thumbnail_file, file_size)
else:
return (False, 400)

if filetype == PDF:
# pdf thumbnails
return create_pdf_thumbnails(repo, file_id, path, size,
thumbnail_file, file_size)
if filetype == XMIND:
return extract_xmind_image(repo_id, path, size)

Expand Down Expand Up @@ -181,6 +185,41 @@ def create_psd_thumbnails(repo, file_id, path, size, thumbnail_file, file_size):
os.unlink(tmp_img_path)
return (False, 500)


def create_pdf_thumbnails(repo, file_id, path, size, thumbnail_file, file_size):
t1 = timeit.default_timer()
token = seafile_api.get_fileserver_access_token(repo.id,
file_id, 'view', '', use_onetime=False)

if not token:
return (False, 500)

inner_path = gen_inner_file_get_url(token, os.path.basename(path))
tmp_path = str(os.path.join(tempfile.gettempdir(), '%s.png' % file_id[:8]))
pdf_file = urllib.request.urlopen(inner_path)
pdf_stream = BytesIO(pdf_file.read())
try:
pdf_doc = fitz_open(stream=pdf_stream)
pdf_stream.close()
page = pdf_doc[0]
pix = page.get_pixmap()
pix.save(tmp_path)
pdf_doc.close()
except Exception as e:
logger.error(e)
return (False, 500)
t2 = timeit.default_timer()
logger.debug('Create PDF thumbnail of [%s](size: %s) takes: %s' % (path, file_size, (t2 - t1)))

try:
ret = _create_thumbnail_common(tmp_path, thumbnail_file, size)
os.unlink(tmp_path)
return ret
except Exception as e:
logger.error(e)
os.unlink(tmp_path)
return (False, 500)

def create_video_thumbnails(repo, file_id, path, size, thumbnail_file, file_size):

t1 = timeit.default_timer()
Expand Down
1 change: 1 addition & 0 deletions seahub/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,7 @@ def react_fake_view(request, **kwargs):
'ocm_remote_servers': OCM_REMOTE_SERVERS,
'enable_share_to_department': settings.ENABLE_SHARE_TO_DEPARTMENT,
'enable_video_thumbnail': settings.ENABLE_VIDEO_THUMBNAIL,
'enable_pdf_thumbnail': settings.ENABLE_PDF_THUMBNAIL,
'group_import_members_extra_msg': GROUP_IMPORT_MEMBERS_EXTRA_MSG,
'request_from_onlyoffice_desktop_editor': ONLYOFFICE_DESKTOP_EDITOR_HTTP_USER_AGENT in request.headers.get('user-agent', ''),
'enable_sso_to_thirdpart_website': settings.ENABLE_SSO_TO_THIRDPART_WEBSITE,
Expand Down
2 changes: 2 additions & 0 deletions seahub/views/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,8 @@ def view_lib_file(request, repo_id, path):
send_file_access_msg(request, repo, path, 'web')
if filetype == VIDEO:
return_dict['enable_video_thumbnail'] = settings.ENABLE_VIDEO_THUMBNAIL
if filetype == PDF:
return_dict['enable_pdf_thumbnail'] = settings.ENABLE_PDF_THUMBNAIL
return render(request, template, return_dict)

elif filetype == XMIND:
Expand Down
3 changes: 2 additions & 1 deletion seahub/views/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
THUMBNAIL_ROOT, THUMBNAIL_DEFAULT_SIZE, THUMBNAIL_SIZE_FOR_GRID, \
MAX_NUMBER_OF_FILES_FOR_FILEUPLOAD, SHARE_LINK_EXPIRE_DAYS_MIN, \
SHARE_LINK_EXPIRE_DAYS_MAX, SEAFILE_COLLAB_SERVER, \
ENABLE_SHARE_LINK_REPORT_ABUSE
ENABLE_SHARE_LINK_REPORT_ABUSE, ENABLE_PDF_THUMBNAIL
from seahub.utils.file_types import IMAGE, VIDEO, XMIND
from seahub.thumbnail.utils import get_share_link_thumbnail_src
from seahub.group.utils import is_group_admin
Expand Down Expand Up @@ -363,6 +363,7 @@ def view_shared_dir(request, fileshare):
'desc_for_ogp': desc_for_ogp,
'enable_share_link_report_abuse': ENABLE_SHARE_LINK_REPORT_ABUSE,
'enable_video_thumbnail': ENABLE_VIDEO_THUMBNAIL,
'enable_pdf_thumbnail': ENABLE_PDF_THUMBNAIL,
})


Expand Down
1 change: 1 addition & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ splinter
pytest==7.4.4
pytest-django
selenium
PyMuPDF
Loading