[Bf-blender-cvs] [ef9269bd62f] master: Thumbnails: refactor extraction to use one code-path for all platforms

Campbell Barton noreply at git.blender.org
Wed Oct 20 01:33:24 CEST 2021


Commit: ef9269bd62f31e39d39cc59cd34354b53eae6661
Author: Campbell Barton
Date:   Wed Oct 20 10:16:36 2021 +1100
Branches: master
https://developer.blender.org/rBef9269bd62f31e39d39cc59cd34354b53eae6661

Thumbnails: refactor extraction to use one code-path for all platforms

Thumbnail extraction now shares code between Linux/Windows,
allowing thumbnails from Zstd compressed blend files to be extracted.

The main logic is placed in blendthumb_extract.cc and is built as static
library. For windows there is DLL which is registered during blender
install and which then reads and generates thumbnails.

For other platforms there is blender-thumbnailer executable file which
takes blend file as an input and generates PNG file. As a result
Python script blender-thumbnailer.py is no longer needed.

The thumbnail extractor shares the same code-path as Blenders file
reading, so there is no need to duplicate any file reading logic.
This means reading compressed blend files is supported (broken since
the recent move Zstd compression - D5799).

This resolves T63736.

Contributors:

- @alausic original patch.
- @LazyDodo windows fixes/support.
- @campbellbarton general fixes/update.
- @lukasstockner97 Zstd support.

Reviewed By: sybren, mont29, LazyDodo, campbellbarton

Ref D6408

===================================================================

D	release/bin/blender-thumbnailer.py
M	source/blender/CMakeLists.txt
M	source/blender/blendthumb/CMakeLists.txt
D	source/blender/blendthumb/src/BlenderThumb.cpp
A	source/blender/blendthumb/src/blender_thumbnailer.cc
A	source/blender/blendthumb/src/blendthumb.hh
A	source/blender/blendthumb/src/blendthumb_extract.cc
A	source/blender/blendthumb/src/blendthumb_png.cc
A	source/blender/blendthumb/src/blendthumb_win32.cc
R100	source/blender/blendthumb/src/BlendThumb.def	source/blender/blendthumb/src/blendthumb_win32.def
R100	source/blender/blendthumb/src/BlendThumb.rc	source/blender/blendthumb/src/blendthumb_win32.rc
R100	source/blender/blendthumb/src/Dll.cpp	source/blender/blendthumb/src/blendthumb_win32_dll.cc
M	source/creator/CMakeLists.txt

===================================================================

diff --git a/release/bin/blender-thumbnailer.py b/release/bin/blender-thumbnailer.py
deleted file mode 100755
index e050a681ca0..00000000000
--- a/release/bin/blender-thumbnailer.py
+++ /dev/null
@@ -1,193 +0,0 @@
-#!/usr/bin/env python3
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  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, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-
-"""
-Thumbnailer runs with python 2.7 and 3.x.
-To run automatically with a file manager such as Nautilus, save this file
-in a directory that is listed in PATH environment variable, and create
-blender.thumbnailer file in ${HOME}/.local/share/thumbnailers/ directory
-with the following contents:
-
-[Thumbnailer Entry]
-TryExec=blender-thumbnailer.py
-Exec=blender-thumbnailer.py %u %o
-MimeType=application/x-blender;
-"""
-
-import struct
-
-
-def open_wrapper_get():
-    """ wrap OS specific read functionality here, fallback to 'open()'
-    """
-
-    class GFileWrapper:
-        __slots__ = ("mode", "g_file")
-
-        def __init__(self, url, mode='r'):
-            self.mode = mode  # used in gzip module
-            self.g_file = Gio.File.parse_name(url).read(None)
-
-        def read(self, size):
-            return self.g_file.read_bytes(size, None).get_data()
-
-        def seek(self, offset, whence=0):
-            self.g_file.seek(offset, [1, 0, 2][whence], None)
-            return self.g_file.tell()
-
-        def tell(self):
-            return self.g_file.tell()
-
-        def close(self):
-            self.g_file.close(None)
-
-    def open_local_url(url, mode='r'):
-        o = urlparse(url)
-        if o.scheme == '':
-            path = o.path
-        elif o.scheme == 'file':
-            path = unquote(o.path)
-        else:
-            raise(IOError('URL scheme "%s" needs gi.repository.Gio module' % o.scheme))
-        return open(path, mode)
-
-    try:
-        from gi.repository import Gio
-        return GFileWrapper
-    except ImportError:
-        try:
-            # Python 3
-            from urllib.parse import urlparse, unquote
-        except ImportError:
-            # Python 2
-            from urlparse import urlparse
-            from urllib import unquote
-        return open_local_url
-
-
-def blend_extract_thumb(path):
-    import os
-    open_wrapper = open_wrapper_get()
-
-    REND = b'REND'
-    TEST = b'TEST'
-
-    blendfile = open_wrapper(path, 'rb')
-
-    head = blendfile.read(12)
-
-    if head[0:2] == b'\x1f\x8b':  # gzip magic
-        import gzip
-        blendfile.close()
-        blendfile = gzip.GzipFile('', 'rb', 0, open_wrapper(path, 'rb'))
-        head = blendfile.read(12)
-
-    if not head.startswith(b'BLENDER'):
-        blendfile.close()
-        return None, 0, 0
-
-    is_64_bit = (head[7] == b'-'[0])
-
-    # true for PPC, false for X86
-    is_big_endian = (head[8] == b'V'[0])
-
-    # blender pre 2.5 had no thumbs
-    if head[9:11] <= b'24':
-        return None, 0, 0
-
-    sizeof_bhead = 24 if is_64_bit else 20
-    int_endian = '>i' if is_big_endian else '<i'
-    int_endian_pair = int_endian + 'i'
-
-    while True:
-        bhead = blendfile.read(sizeof_bhead)
-
-        if len(bhead) < sizeof_bhead:
-            return None, 0, 0
-
-        code = bhead[:4]
-        length = struct.unpack(int_endian, bhead[4:8])[0]  # 4 == sizeof(int)
-
-        if code == REND:
-            blendfile.seek(length, os.SEEK_CUR)
-        else:
-            break
-
-    if code != TEST:
-        return None, 0, 0
-
-    try:
-        x, y = struct.unpack(int_endian_pair, blendfile.read(8))  # 8 == sizeof(int) * 2
-    except struct.error:
-        return None, 0, 0
-
-    length -= 8  # sizeof(int) * 2
-
-    if length != x * y * 4:
-        return None, 0, 0
-
-    image_buffer = blendfile.read(length)
-
-    if len(image_buffer) != length:
-        return None, 0, 0
-
-    return image_buffer, x, y
-
-
-def write_png(buf, width, height):
-    import zlib
-
-    # reverse the vertical line order and add null bytes at the start
-    width_byte_4 = width * 4
-    raw_data = b"".join(b'\x00' + buf[span:span + width_byte_4] for span in range((height - 1) * width * 4, -1, - width_byte_4))
-
-    def png_pack(png_tag, data):
-        chunk_head = png_tag + data
-        return struct.pack("!I", len(data)) + chunk_head + struct.pack("!I", 0xFFFFFFFF & zlib.crc32(chunk_head))
-
-    return b"".join([
-        b'\x89PNG\r\n\x1a\n',
-        png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, 6, 0, 0, 0)),
-        png_pack(b'IDAT', zlib.compress(raw_data, 9)),
-        png_pack(b'IEND', b'')])
-
-
-def main():
-    import sys
-
-    if len(sys.argv) < 3:
-        print("Expected 2 arguments <input.blend> <output.png>")
-    else:
-        file_in = sys.argv[-2]
-
-        buf, width, height = blend_extract_thumb(file_in)
-
-        if buf:
-            file_out = sys.argv[-1]
-
-            f = open(file_out, "wb")
-            f.write(write_png(buf, width, height))
-            f.close()
-
-
-if __name__ == '__main__':
-    main()
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 84d31bccc53..0a494677d96 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -131,6 +131,7 @@ add_subdirectory(io)
 add_subdirectory(functions)
 add_subdirectory(makesdna)
 add_subdirectory(makesrna)
+add_subdirectory(blendthumb)
 
 if(WITH_COMPOSITOR)
   add_subdirectory(compositor)
@@ -159,7 +160,3 @@ endif()
 if(WITH_FREESTYLE)
   add_subdirectory(freestyle)
 endif()
-
-if(WIN32)
-  add_subdirectory(blendthumb)
-endif()
diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt
index b42ca284ecb..4bcd27082c0 100644
--- a/source/blender/blendthumb/CMakeLists.txt
+++ b/source/blender/blendthumb/CMakeLists.txt
@@ -19,23 +19,59 @@
 # ***** END GPL LICENSE BLOCK *****
 
 #-----------------------------------------------------------------------------
-include_directories(${ZLIB_INCLUDE_DIRS})
+# Shared Thumbnail Extraction Logic
+
+include_directories(
+  ../blenlib
+  ../makesdna
+  ../../../intern/guardedalloc
+)
+
+include_directories(
+  SYSTEM
+  ${ZLIB_INCLUDE_DIRS}
+)
 
 set(SRC
-  src/BlenderThumb.cpp
-  src/BlendThumb.def
-  src/BlendThumb.rc
-  src/Dll.cpp
+  src/blendthumb.hh
+  src/blendthumb_extract.cc
+  src/blendthumb_png.cc
 )
 
-string(APPEND CMAKE_SHARED_LINKER_FLAGS_DEBUG " /nodefaultlib:MSVCRT.lib")
+if(WIN32)
+  # -----------------------------------------------------------------------------
+  # Build `BlendThumb.dll`
 
-add_library(BlendThumb SHARED ${SRC})
-setup_platform_linker_flags(BlendThumb)
-target_link_libraries(BlendThumb ${ZLIB_LIBRARIES})
+  set(SRC_WIN32
+    src/blendthumb_win32.cc
+    src/blendthumb_win32.def
+    src/blendthumb_win32.rc
+    src/blendthumb_win32_dll.cc
+  )
 
-install(
-  FILES $<TARGET_FILE:BlendThumb>
-  COMPONENT Blender
-  DESTINATION "."
-)
+  add_definitions(-DNOMINMAX)
+
+  add_library(BlendThumb SHARED ${SRC} ${SRC_WIN32})
+
+  target_link_libraries(BlendThumb bf_blenlib dbghelp.lib Version.lib)
+  set_target_properties(BlendThumb PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB:msvcrt")
+
+  install(
+    FILES $<TARGET_FILE:BlendThumb>
+    COMPONENT Blender
+    DESTINATION "."
+  )
+else()
+  # -----------------------------------------------------------------------------
+  # Build `blender-thumbnailer` executable
+
+  add_executable(blender-thumbnailer ${SRC} src/blender_thumbnailer.cc)
+  target_link_libraries(blender-thumbnailer bf_blenlib)
+  target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES})
+
+  install(
+    FILES $<TARGET_FILE:blender-thumbnailer>
+    COMPONENT Blender
+    DESTINATION "."
+  )
+endif()
diff --git a/source/blender/blendthumb/src/BlenderThumb.cpp b/source/blender/blendthumb/src/BlenderThumb.cpp
deleted file mode 100644
index 939e7bbf67c..00000000000
--- a/source/blender/blendthumb/src/BlenderThumb.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * 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, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <new>
-#include <shlwapi.h>
-#include <thumbcache.h>  // For IThumbnailProvider.
-
-#pragma comment(lib, "shlwapi.lib")
-
-// this thumbnail provider implements IInitializeWithStream to enable being hosted
-// in an isolated process for robustness
-
-class CBlendThumb : public IInitializeWithStream, public IThumbnailProvider {
- public:
-  CBlendThumb() : _cRef(1), _pStream(NULL)
-  {
-  }
-
-  virtual ~CBlendThumb()
-  {
-    if (_pStream) {
-      _pStream->Release();
-    }
-  }
-
-  // IUnknown
-  IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
-  {
-    static const QITAB qit[] = {
-        QITABENT(CBlendThumb, IInitializeWithStream),
-        QITABENT(CBlendThumb, IThumbnailProvider),
-        {0},
-    };
-    return QISearch(this, qit, riid, ppv);
-  }
-
-  IFACEMETHODIMP_(ULONG) AddRef()

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list