[client] add SVG loading support and use icons for status display

This brings nanosvg into the project for SVG loading and rendering.
Unfortunatly we can not at this time use a submodule for this project
until https://github.com/memononen/nanosvg/pull/214 is merged.
This commit is contained in:
Geoffrey McRae 2022-05-26 04:08:22 +10:00
parent 8aa36144dc
commit 8974ae4fb5
19 changed files with 4947 additions and 92 deletions

View File

@ -110,7 +110,10 @@ add_custom_command(
include_directories( include_directories(
${PROJECT_TOP} ${PROJECT_TOP}
${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}/include ${CMAKE_BINARY_DIR}/include
${PROJECT_TOP}/repos/nanosvg/src
) )
link_libraries( link_libraries(
@ -142,12 +145,13 @@ set(SOURCES
src/overlay/help.c src/overlay/help.c
src/overlay/config.c src/overlay/config.c
src/overlay/msg.c src/overlay/msg.c
src/overlay/record.c src/overlay/status.c
) )
# Force cimgui to build as a static library. # Force cimgui to build as a static library.
set(IMGUI_STATIC "yes" CACHE STRING "Build as a static library") set(IMGUI_STATIC "yes" CACHE STRING "Build as a static library")
add_subdirectory("${PROJECT_TOP}/resources" "${CMAKE_BINARY_DIR}/resources")
add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common" ) add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common" )
add_subdirectory("${PROJECT_TOP}/repos/LGMP/lgmp" "${CMAKE_BINARY_DIR}/LGMP" ) add_subdirectory("${PROJECT_TOP}/repos/LGMP/lgmp" "${CMAKE_BINARY_DIR}/LGMP" )
add_subdirectory("${PROJECT_TOP}/repos/PureSpice" "${CMAKE_BINARY_DIR}/PureSpice") add_subdirectory("${PROJECT_TOP}/repos/PureSpice" "${CMAKE_BINARY_DIR}/PureSpice")
@ -163,6 +167,7 @@ target_compile_definitions(looking-glass-client PRIVATE CIMGUI_DEFINE_ENUMS_AND_
target_link_libraries(looking-glass-client target_link_libraries(looking-glass-client
${EXE_FLAGS} ${EXE_FLAGS}
PkgConfig::FONTCONFIG PkgConfig::FONTCONFIG
lg_resources
lg_common lg_common
displayservers displayservers
lgmp lgmp

View File

@ -172,6 +172,17 @@ typedef struct LG_RendererOps
const bool newFrame, const bool invalidateWindow, const bool newFrame, const bool invalidateWindow,
void (*preSwap)(void * udata), void * udata); void (*preSwap)(void * udata), void * udata);
/* called to create a texture from the specified 32-bit RGB image data. This
* method is for use with Dear ImGui
* Context: renderThread */
void * (*createTexture)(LG_Renderer * renderer,
int width, int height, uint8_t * data);
/* called to free a texture previously created by createTexture. This method
* is for use with Dear ImGui
* Context: renderThread */
void (*freeTexture)(LG_Renderer * renderer, void * texture);
/* setup the spice display */ /* setup the spice display */
void (*spiceConfigure)(LG_Renderer * renderer, int width, int height); void (*spiceConfigure)(LG_Renderer * renderer, int width, int height);

View File

@ -27,9 +27,23 @@
typedef struct ImVec2 ImVec2; typedef struct ImVec2 ImVec2;
typedef struct
{
void * tex;
int width;
int height;
}
OverlayImage;
void overlayGetImGuiRect(struct Rect * rect); void overlayGetImGuiRect(struct Rect * rect);
ImVec2 * overlayGetScreenSize(void); ImVec2 * overlayGetScreenSize(void);
void overlayTextURL(const char * url, const char * text); void overlayTextURL(const char * url, const char * text);
void overlayTextMaybeURL(const char * text, bool wrapped); void overlayTextMaybeURL(const char * text, bool wrapped);
// create a texture from a SVG and scale it to fit the supplied width & height
bool overlayLoadSVG(const char * data, unsigned int size, OverlayImage * image,
int width, int height);
void overlayFreeImage(OverlayImage * image);
#endif #endif

View File

@ -1210,6 +1210,41 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
return true; return true;
} }
static void * egl_createTexture(LG_Renderer * renderer,
int width, int height, uint8_t * data)
{
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
width,
height,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
data);
glBindTexture(GL_TEXTURE_2D, 0);
return (void*)(intptr_t)tex;
}
static void egl_freeTexture(LG_Renderer * renderer, void * texture)
{
GLuint tex = (GLuint)(intptr_t)texture;
glDeleteTextures(1, &tex);
}
static void egl_spiceConfigure(LG_Renderer * renderer, int width, int height) static void egl_spiceConfigure(LG_Renderer * renderer, int width, int height)
{ {
struct Inst * this = UPCAST(struct Inst, renderer); struct Inst * this = UPCAST(struct Inst, renderer);
@ -1257,6 +1292,8 @@ struct LG_RendererOps LGR_EGL =
.renderStartup = egl_renderStartup, .renderStartup = egl_renderStartup,
.needsRender = egl_needsRender, .needsRender = egl_needsRender,
.render = egl_render, .render = egl_render,
.createTexture = egl_createTexture,
.freeTexture = egl_freeTexture,
.spiceConfigure = egl_spiceConfigure, .spiceConfigure = egl_spiceConfigure,
.spiceDrawFill = egl_spiceDrawFill, .spiceDrawFill = egl_spiceDrawFill,

View File

@ -663,6 +663,41 @@ static void renderWait(struct Inst * this)
glDisable(GL_BLEND); glDisable(GL_BLEND);
} }
static void * opengl_createTexture(LG_Renderer * renderer,
int width, int height, uint8_t * data)
{
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
width,
height,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
data);
glBindTexture(GL_TEXTURE_2D, 0);
return (void*)(intptr_t)tex;
}
static void opengl_freeTexture(LG_Renderer * renderer, void * texture)
{
GLuint tex = (GLuint)(intptr_t)texture;
glDeleteTextures(1, &tex);
}
static void opengl_spiceConfigure(LG_Renderer * renderer, int width, int height) static void opengl_spiceConfigure(LG_Renderer * renderer, int width, int height)
{ {
struct Inst * this = UPCAST(struct Inst, renderer); struct Inst * this = UPCAST(struct Inst, renderer);
@ -797,6 +832,8 @@ const LG_RendererOps LGR_OpenGL =
.renderStartup = opengl_renderStartup, .renderStartup = opengl_renderStartup,
.needsRender = opengl_needsRender, .needsRender = opengl_needsRender,
.render = opengl_render, .render = opengl_render,
.createTexture = opengl_createTexture,
.freeTexture = opengl_freeTexture,
.spiceConfigure = opengl_spiceConfigure, .spiceConfigure = opengl_spiceConfigure,
.spiceDrawFill = opengl_spiceDrawFill, .spiceDrawFill = opengl_spiceDrawFill,

View File

@ -676,7 +676,7 @@ void app_msgBoxClose(MsgBoxHandle handle)
void app_showRecord(bool show) void app_showRecord(bool show)
{ {
overlayRecord_show(show); overlayStatus_set(LG_USER_STATUS_RECORDING, show);
} }
KeybindHandle app_registerKeybind(int sc, KeybindFn callback, void * opaque, const char * description) KeybindHandle app_registerKeybind(int sc, KeybindFn callback, void * opaque, const char * description)
@ -1072,4 +1072,5 @@ void app_useSpiceDisplay(bool enable)
renderQueue_spiceShow(false); renderQueue_spiceShow(false);
purespice_disconnectChannel(PS_CHANNEL_DISPLAY); purespice_disconnectChannel(PS_CHANNEL_DISPLAY);
} }
overlayStatus_set(LG_USER_STATUS_SPICE, enable);
} }

View File

@ -1725,7 +1725,7 @@ int main(int argc, char * argv[])
app_registerOverlay(&LGOverlayGraphs, NULL); app_registerOverlay(&LGOverlayGraphs, NULL);
app_registerOverlay(&LGOverlayHelp , NULL); app_registerOverlay(&LGOverlayHelp , NULL);
app_registerOverlay(&LGOverlayMsg , NULL); app_registerOverlay(&LGOverlayMsg , NULL);
app_registerOverlay(&LGOverlayRecord, NULL); app_registerOverlay(&LGOverlayStatus, NULL);
// early renderer setup for option registration // early renderer setup for option registration
for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i) for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i)

View File

@ -1,87 +0,0 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* https://looking-glass.io
*
* 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., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "interface/overlay.h"
#include "cimgui.h"
#include "overlay_utils.h"
#include "common/stringutils.h"
#include "../main.h"
static bool recordShow = false;
static bool recordToggle = false;
static unsigned long long lastTick = 0;
static bool record_init(void ** udata, const void * params)
{
return true;
}
static void record_free(void * udata)
{}
static int record_render(void * udata, bool interactive, struct Rect * windowRects,
int maxRects)
{
if (!recordShow || !recordToggle)
return 0;
ImVec2 * screen = overlayGetScreenSize();
ImDrawList_AddCircleFilled(igGetBackgroundDrawList_Nil(),
(ImVec2) { screen->x - 20.0f, 20.0f },
5.0f, 0xFF0000FF, 0
);
*windowRects = (struct Rect) {
.x = screen->x - 26, .y = 14, .w = 12, .h = 12
};
return 1;
}
static bool record_tick(void * udata, unsigned long long tickCount)
{
if (tickCount - lastTick >= 25)
{
recordToggle = !recordToggle;
lastTick = tickCount;
return true;
}
return false;
}
struct LG_OverlayOps LGOverlayRecord =
{
.name = "record",
.init = record_init,
.free = record_free,
.render = record_render,
.tick = record_tick,
};
void overlayRecord_show(bool show)
{
if (show == recordShow)
return;
recordShow = show;
if (g_state.state != APP_STATE_SHUTDOWN)
app_invalidateOverlay(true);
}

134
client/src/overlay/status.c Normal file
View File

@ -0,0 +1,134 @@
/**
* Looking Glass
* Copyright © 2017-2022 The Looking Glass Authors
* https://looking-glass.io
*
* 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., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "interface/overlay.h"
#include "cimgui.h"
#include "../overlays.h"
#include "../main.h"
#include "overlay_utils.h"
#include "resources/status/recording.svg.h"
#include "resources/status/spice.svg.h"
//TODO: Make this user configurable?
#define ICON_SIZE 32
static bool l_state[LG_USER_STATUS_MAX] = { 0 };
static OverlayImage l_image[LG_USER_STATUS_MAX] = { 0 };
static bool l_recordToggle;
static bool status_init(void ** udata, const void * params)
{
overlayLoadSVG(b_status_recording_svg, b_status_recording_svg_size,
&l_image[LG_USER_STATUS_RECORDING], ICON_SIZE, ICON_SIZE);
overlayLoadSVG(b_status_spice_svg, b_status_spice_svg_size,
&l_image[LG_USER_STATUS_SPICE], ICON_SIZE, ICON_SIZE);
return true;
}
static void status_free(void * udata)
{
for(int i = 0; i < LG_USER_STATUS_MAX; ++i)
overlayFreeImage(&l_image[i]);
}
static int status_render(void * udata, bool interactive, struct Rect * windowRects,
int maxRects)
{
const int marginX = 10;
const int marginY = 10;
const int gapX = 5;
ImVec2 * screen = overlayGetScreenSize();
struct Rect rect = {
.x = screen->x - LG_USER_STATUS_MAX * (ICON_SIZE + gapX) - marginX,
.y = marginY,
.w = LG_USER_STATUS_MAX * (ICON_SIZE + gapX),
.h = ICON_SIZE
};
int xPos = screen->x - marginX;
for(int i = 0; i < LG_USER_STATUS_MAX; ++i)
{
OverlayImage * img = &l_image[i];
if (!l_state[i] || !img->tex)
continue;
// if the recording indicator is off, don't draw but reserve space
if (i == LG_USER_STATUS_RECORDING && !l_recordToggle)
goto next;
ImDrawList_AddImage(
igGetBackgroundDrawList_Nil(),
img->tex,
(ImVec2){
xPos,
marginY
},
(ImVec2){
xPos - ICON_SIZE,
img->height + marginY
},
(ImVec2){ 0, 0 },
(ImVec2){ 1, 1 },
0xFFFFFFFF);
next:
xPos -= ICON_SIZE + gapX;
}
*windowRects = rect;
return 1;
}
static bool status_tick(void * udata, unsigned long long tickCount)
{
static unsigned long long lastTick = 0;
if (tickCount - lastTick >= 25)
{
l_recordToggle = !l_recordToggle;
lastTick = tickCount;
return true;
}
return false;
}
struct LG_OverlayOps LGOverlayStatus =
{
.name = "status",
.init = status_init,
.free = status_free,
.render = status_render,
.tick = status_tick,
};
void overlayStatus_set(LGUserStatus status, bool value)
{
if (l_state[status] == value)
return;
l_state[status] = value;
app_invalidateOverlay(true);
};

View File

@ -26,6 +26,11 @@
#include "cimgui.h" #include "cimgui.h"
#include "main.h" #include "main.h"
#define NANOSVG_IMPLEMENTATION
#define NANOSVG_ALL_COLOR_KEYWORDS
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"
void overlayGetImGuiRect(struct Rect * rect) void overlayGetImGuiRect(struct Rect * rect)
{ {
ImVec2 size; ImVec2 size;
@ -78,3 +83,93 @@ void overlayTextMaybeURL(const char * text, bool wrapped)
else else
igText(text); igText(text);
} }
bool overlayLoadSVG(const char * data, unsigned int size, OverlayImage * image,
int width, int height)
{
image->tex = NULL;
//nsvgParse alters the data, we need to make a copy and null terminate it
char * svg = malloc(size + 1);
if (!svg)
{
DEBUG_ERROR("out of ram");
goto err;
}
memcpy(svg, data, size);
svg[size] = 0;
NSVGimage * nvi = nsvgParse(svg, "px", 96.0);
if (!nvi)
{
free(svg);
DEBUG_ERROR("nvsgParseFromData failed");
goto err;
}
free(svg);
NSVGrasterizer * rast = nsvgCreateRasterizer();
if (!rast)
{
DEBUG_ERROR("nsvgCreateRasterizer failed");
goto err_image;
}
double srcAspect = nvi->width / nvi->height;
double dstAspect = (double)width / (double)height;
float scale;
if (dstAspect > srcAspect)
{
image->width = (double)height * srcAspect;
image->height = height;
scale = (float)image->width / nvi->width;
}
else
{
image->width = width;
image->height = (double)width / srcAspect;
scale = (float)image->height / nvi->height;
}
uint8_t * img = malloc(image->width * image->height * 4);
if (!img)
{
DEBUG_ERROR("out of ram");
goto err_rast;
}
nsvgRasterize(rast, nvi,
0.0f, 0.0f,
scale,
img,
image->width,
image->height,
image->width * 4);
image->tex = RENDERER(createTexture, image->width, image->height, img);
free(img);
if (!image->tex)
{
DEBUG_ERROR("renderer failed to create the texture");
goto err_rast;
}
err_rast:
nsvgDeleteRasterizer(rast);
err_image:
nsvgDelete(nvi);
err:
return image->tex != NULL;
}
void overlayFreeImage(OverlayImage * image)
{
if (!image->tex)
return;
RENDERER(freeTexture, image->tex);
}

View File

@ -39,7 +39,7 @@ extern struct LG_OverlayOps LGOverlayGraphs;
extern struct LG_OverlayOps LGOverlayHelp; extern struct LG_OverlayOps LGOverlayHelp;
extern struct LG_OverlayOps LGOverlayConfig; extern struct LG_OverlayOps LGOverlayConfig;
extern struct LG_OverlayOps LGOverlayMsg; extern struct LG_OverlayOps LGOverlayMsg;
extern struct LG_OverlayOps LGOverlayRecord; extern struct LG_OverlayOps LGOverlayStatus;
void overlayAlert_show(LG_MsgAlert type, const char * fmt, va_list args); void overlayAlert_show(LG_MsgAlert type, const char * fmt, va_list args);
@ -56,6 +56,14 @@ void overlayConfig_register(const char * title,
void overlayConfig_registerTab(const char * title, void overlayConfig_registerTab(const char * title,
void (*callback)(void * udata, int * id), void * udata); void (*callback)(void * udata, int * id), void * udata);
void overlayRecord_show(bool show); typedef enum LG_UserStatus
{
LG_USER_STATUS_SPICE,
LG_USER_STATUS_RECORDING,
LG_USER_STATUS_MAX
}
LGUserStatus;
void overlayStatus_set(LGUserStatus, bool value);
#endif #endif

31
repos/nanosvg/.gitignore vendored Normal file
View File

@ -0,0 +1,31 @@
## Compiled source #
*.com
*.class
*.dll
*.exe
*.o
*.so
test
## Logs and databases #
*.log
*.sql
*.sqlite
## OS generated files #
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
## Build dir
build/*
## Stuff in example
example/_*
## xcode specific
*xcuserdata*

18
repos/nanosvg/LICENSE.txt Normal file
View File

@ -0,0 +1,18 @@
Copyright (c) 2013-14 Mikko Mononen memon@inside.org
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of 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. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

3010
repos/nanosvg/src/nanosvg.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

23
resources/CMakeLists.txt Normal file
View File

@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.0)
project(lg_resources LANGUAGES C)
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
include(MakeObject)
function(build_resources)
make_object(
LG_RESOURCES
${ARGN}
)
set(LG_RESOURCES_OBJS "${LG_RESOURCES_OBJS}" PARENT_SCOPE)
set(LG_RESOURCES_INCS "${LG_RESOURCES_INCS}" PARENT_SCOPE)
endfunction()
build_resources(
status/spice.svg
status/recording.svg
)
add_library(lg_resources STATIC ${LG_RESOURCES_OBJS})
set_target_properties(lg_resources PROPERTIES LINKER_LANGUAGE C)

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50 (54983) - http://www.bohemiancoding.com/sketch -->
<title>32. Microphone</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="32.-Microphone" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g transform="translate(20.000000, 2.000000)" stroke="#FF6B6B" stroke-width="4">
<rect id="Layer-1" x="10" y="0" width="40" height="70" rx="20"></rect>
<path d="M59.1760883,56 C56.0189777,69.1888659 44.1567785,78.9927367 30,78.9927367 C15.8460957,78.9927367 3.98153075,69.1900571 0.823950814,56" id="Layer-2"></path>
<path d="M30,78.9687805 L30,95" id="Layer-3"></path>
<path d="M10,96 L50,96" id="Layer-4"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 996 B

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_3" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
<g>
<path style="fill:#88929F;" d="M58,2H36.667L35,4l2,4l-0.001,4L40,15l-8,17l-5-12l4-9l-4.5-9H6C3.791,2,2,3.791,2,6v40
c0,2.209,1.791,4,4,4h52c2.209,0,4-1.791,4-4V6C62,3.791,60.209,2,58,2z"/>
<polygon style="fill:#C7E2FB;" points="58,6 36,6 37,8 36.999,12 40,15 32,32 27,20 31,11 28.5,6 6,6 6,42 58,42 "/>
<polygon style="fill:#C7E2FB;" points="58,6 36,6 37,8 36.999,12 40,15 32,32 27,20 31,11 28.5,6 6,6 6,42 58,42 "/>
<path style="fill:#EBF7FE;" d="M36,6l1,2l-0.001,4L40,15l-8,17l-5-12l4-9l-2.5-5H6v33h44c2.209,0,4-1.791,4-4V6H36z"/>
<path style="fill:#88929F;" d="M45,58c1.105,0,2,0.895,2,2v2H17v-2c0-1.105,0.895-2,2-2H45z"/>
<rect x="23" y="50" style="fill:#A0A8B2;" width="18" height="8"/>
<polygon style="fill:#FFFFFF;" points="21,35 19,30 24,31 "/>
<polygon style="fill:#FFFFFF;" points="43,38 45,33 40,34 "/>
<g>
<path style="fill:#D9DCE0;" d="M57,47h-8c-0.552,0-1-0.448-1-1l0,0c0-0.552,0.448-1,1-1h8c0.552,0,1,0.448,1,1l0,0
C58,46.552,57.552,47,57,47z"/>
</g>
<g>
<path style="fill:#D9DCE0;" d="M45,47h-4c-0.552,0-1-0.448-1-1l0,0c0-0.552,0.448-1,1-1h4c0.552,0,1,0.448,1,1l0,0
C46,46.552,45.552,47,45,47z"/>
</g>
<g>
<path d="M58,1H36.667c-0.297,0-0.578,0.132-0.768,0.36l-1.667,2c-0.254,0.305-0.304,0.732-0.126,1.087L36,8.236L35.999,12
c0,0.265,0.105,0.52,0.293,0.707l2.504,2.503l-6.74,14.323l-3.967-9.521l3.825-8.606c0.122-0.273,0.114-0.586-0.019-0.854l-4.5-9
C27.225,1.214,26.879,1,26.5,1H6C3.243,1,1,3.243,1,6v40c0,2.757,2.243,5,5,5h16v6h-3c-1.654,0-3,1.346-3,3v2c0,0.552,0.448,1,1,1
h30c0.552,0,1-0.448,1-1v-2c0-1.654-1.346-3-3-3h-3v-6h16c2.757,0,5-2.243,5-5V6C63,3.243,60.757,1,58,1z M26.35,19h-5.936
L18,16.586V13h-2v4c0,0.265,0.105,0.52,0.293,0.707L18.586,20l-4.293,4.293l1.414,1.414L20.414,21h5.919l4.744,11.385
c0.152,0.365,0.505,0.606,0.9,0.615c0.389,0.018,0.759-0.216,0.927-0.574l7.449-15.829l4.711,3.926l0.946,6.62l1.979-0.283
l-0.929-6.505L49.414,18H53v-2h-4c-0.265,0-0.52,0.105-0.707,0.293l-2.354,2.354l-5.263-4.386l-2.676-2.675L38,8
c0-0.155-0.036-0.308-0.105-0.447L37.618,7H57v34H7V7h20.882l2.013,4.025L26.35,19z M46,60v1H18v-1c0-0.551,0.449-1,1-1h26
C45.551,59,46,59.449,46,60z M40,57H24v-6h16V57z M61,46c0,1.654-1.346,3-3,3H6c-1.654,0-3-1.346-3-3V6c0-1.654,1.346-3,3-3
h19.882l1,2H6C5.448,5,5,5.448,5,6v36c0,0.552,0.448,1,1,1h52c0.552,0,1-0.448,1-1V6c0-0.552-0.448-1-1-1H36.618l-0.431-0.862
L37.135,3H58c1.654,0,3,1.346,3,3V46z"/>
<path d="M20.071,35.372c0.134,0.335,0.439,0.572,0.797,0.62C20.913,35.997,20.957,36,21,36c0.312,0,0.61-0.146,0.8-0.4l3-4
c0.206-0.275,0.257-0.636,0.134-0.957s-0.401-0.556-0.738-0.624l-5-1c-0.361-0.071-0.73,0.059-0.965,0.341
c-0.235,0.282-0.296,0.67-0.16,1.011L20.071,35.372z M22.248,31.669l-0.98,1.307l-0.653-1.634L22.248,31.669z"/>
<path d="M42.2,38.6c0.19,0.253,0.487,0.4,0.8,0.4c0.043,0,0.087-0.003,0.131-0.009c0.358-0.047,0.663-0.284,0.797-0.62l2-5
c0.136-0.341,0.075-0.729-0.16-1.011c-0.234-0.282-0.603-0.415-0.965-0.341l-5,1c-0.336,0.067-0.615,0.303-0.738,0.624
S38.994,34.325,39.2,34.6L42.2,38.6z M43.386,34.343l-0.653,1.634l-0.98-1.307L43.386,34.343z"/>
<rect x="40" y="25" width="2" height="2"/>
<rect x="20" y="10" width="2" height="2"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB