mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
configurable stream resolution
This commit is contained in:
parent
0468100bba
commit
52d2b8a315
@ -36,14 +36,13 @@ kvmd:
|
||||
init_restart_after: 1.0
|
||||
shutdown_delay: 10.0
|
||||
|
||||
size:
|
||||
width: 800
|
||||
height: 600
|
||||
resolutions:
|
||||
- 800x600 - 720x576
|
||||
|
||||
cmd:
|
||||
- "/usr/bin/mjpg_streamer"
|
||||
- "-i"
|
||||
- "input_uvc.so -d /dev/kvmd-streamer -e 2 -t pal -y -n -r 720x576"
|
||||
- "input_uvc.so -d /dev/kvmd-streamer -e 2 -t pal -y -n -r {resolution}"
|
||||
- "-o"
|
||||
- "output_http.so -l localhost -p 8082"
|
||||
|
||||
|
||||
@ -49,8 +49,7 @@ def main() -> None:
|
||||
sync_delay=float(config["streamer"]["sync_delay"]),
|
||||
init_delay=float(config["streamer"]["init_delay"]),
|
||||
init_restart_after=float(config["streamer"]["init_restart_after"]),
|
||||
width=int(config["streamer"]["size"]["width"]),
|
||||
height=int(config["streamer"]["size"]["height"]),
|
||||
resolutions=config["streamer"]["resolutions"],
|
||||
cmd=list(map(str, config["streamer"]["cmd"])),
|
||||
loop=loop,
|
||||
)
|
||||
|
||||
@ -128,6 +128,7 @@ class Server: # pylint: disable=too-many-instance-attributes
|
||||
self.__system_tasks: List[asyncio.Task] = []
|
||||
|
||||
self.__reset_streamer = False
|
||||
self.__streamer_resolution = streamer.get_current_resolution()
|
||||
|
||||
def run(self, host: str, port: int) -> None:
|
||||
self.__hid.start()
|
||||
@ -148,6 +149,7 @@ class Server: # pylint: disable=too-many-instance-attributes
|
||||
app.router.add_post("/msd/write", self.__msd_write_handler)
|
||||
|
||||
app.router.add_get("/streamer", self.__streamer_state_handler)
|
||||
app.router.add_post("/streamer/set_params", self.__streamer_set_params_handler)
|
||||
app.router.add_post("/streamer/reset", self.__streamer_reset_handler)
|
||||
|
||||
app.on_shutdown.append(self.__on_shutdown)
|
||||
@ -301,6 +303,18 @@ class Server: # pylint: disable=too-many-instance-attributes
|
||||
async def __streamer_state_handler(self, _: aiohttp.web.Request) -> aiohttp.web.Response:
|
||||
return _json(self.__streamer.get_state())
|
||||
|
||||
@_wrap_exceptions_for_web("Can't set stream params")
|
||||
async def __streamer_set_params_handler(self, request: aiohttp.web.Request) -> aiohttp.web.Response:
|
||||
resolution = request.query.get("resolution")
|
||||
if resolution:
|
||||
if resolution in self.__streamer.get_available_resolutions():
|
||||
if resolution != self.__streamer_resolution:
|
||||
self.__streamer_resolution = resolution
|
||||
self.__reset_streamer = True
|
||||
else:
|
||||
raise BadRequest("Unknown resolution %r" % (resolution))
|
||||
return _json()
|
||||
|
||||
async def __streamer_reset_handler(self, _: aiohttp.web.Request) -> aiohttp.web.Response:
|
||||
self.__reset_streamer = True
|
||||
return _json()
|
||||
@ -344,17 +358,20 @@ class Server: # pylint: disable=too-many-instance-attributes
|
||||
cur = len(self.__sockets)
|
||||
if prev == 0 and cur > 0:
|
||||
if not self.__streamer.is_running():
|
||||
await self.__streamer.start()
|
||||
await self.__streamer.start(self.__streamer_resolution)
|
||||
await self.__broadcast_event("streamer_state", **self.__streamer.get_state())
|
||||
elif prev > 0 and cur == 0:
|
||||
shutdown_at = time.time() + self.__streamer_shutdown_delay
|
||||
elif prev == 0 and cur == 0 and time.time() > shutdown_at:
|
||||
if self.__streamer.is_running():
|
||||
await self.__streamer.stop()
|
||||
await self.__broadcast_event("streamer_state", **self.__streamer.get_state())
|
||||
|
||||
if self.__reset_streamer:
|
||||
if self.__streamer.is_running():
|
||||
await self.__streamer.stop()
|
||||
await self.__streamer.start(no_init_restart=True)
|
||||
await self.__streamer.start(self.__streamer_resolution, no_init_restart=True)
|
||||
await self.__broadcast_event("streamer_state", **self.__streamer.get_state())
|
||||
self.__reset_streamer = False
|
||||
|
||||
prev = cur
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import asyncio
|
||||
import asyncio.subprocess
|
||||
|
||||
from collections import OrderedDict as odict
|
||||
|
||||
from typing import List
|
||||
from typing import Dict
|
||||
from typing import Optional
|
||||
@ -20,8 +22,7 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
init_delay: float,
|
||||
init_restart_after: float,
|
||||
|
||||
width: int,
|
||||
height: int,
|
||||
resolutions: List[str],
|
||||
cmd: List[str],
|
||||
|
||||
loop: asyncio.AbstractEventLoop,
|
||||
@ -33,17 +34,25 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
self.__init_delay = init_delay
|
||||
self.__init_restart_after = init_restart_after
|
||||
|
||||
self.__width = width
|
||||
self.__height = height
|
||||
self.__resolutions = odict([
|
||||
(display, (real or display))
|
||||
for (display, real) in [
|
||||
(tuple(map(str.lower, map(str.strip, resolution.split("-", maxsplit=1)))) + ("",))[:2]
|
||||
for resolution in resolutions
|
||||
]
|
||||
])
|
||||
self.__resolution = list(self.__resolutions)[0]
|
||||
self.__cmd = cmd
|
||||
|
||||
self.__loop = loop
|
||||
|
||||
self.__proc_task: Optional[asyncio.Task] = None
|
||||
|
||||
async def start(self, no_init_restart: bool=False) -> None:
|
||||
async def start(self, resolution: str, no_init_restart: bool=False) -> None:
|
||||
logger = get_logger()
|
||||
logger.info("Starting streamer ...")
|
||||
assert resolution in self.__resolutions, (resolution, self.__resolutions)
|
||||
self.__resolution = resolution
|
||||
await self.__inner_start()
|
||||
if self.__init_restart_after > 0.0 and not no_init_restart:
|
||||
logger.info("Stopping streamer to restart ...")
|
||||
@ -58,13 +67,22 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
def is_running(self) -> bool:
|
||||
return bool(self.__proc_task)
|
||||
|
||||
def get_current_resolution(self) -> str:
|
||||
return self.__resolution
|
||||
|
||||
def get_available_resolutions(self) -> List[str]:
|
||||
return list(self.__resolutions)
|
||||
|
||||
def get_state(self) -> Dict:
|
||||
(width, height) = tuple(map(int, self.__resolution.split("x")))
|
||||
return {
|
||||
"is_running": self.is_running(),
|
||||
"size": {
|
||||
"width": self.__width,
|
||||
"height": self.__height,
|
||||
"width": width,
|
||||
"height": height,
|
||||
},
|
||||
"resolution": self.__resolution,
|
||||
"resolutions": list(self.__resolutions),
|
||||
}
|
||||
|
||||
async def cleanup(self) -> None:
|
||||
@ -100,7 +118,7 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
while True: # pylint: disable=too-many-nested-blocks
|
||||
proc: Optional[asyncio.subprocess.Process] = None # pylint: disable=no-member
|
||||
try:
|
||||
cmd = [part.format(width=self.__width, height=self.__height) for part in self.__cmd]
|
||||
cmd = [part.format(resolution=self.__resolutions[self.__resolution]) for part in self.__cmd]
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
|
||||
@ -36,14 +36,15 @@ kvmd:
|
||||
init_restart_after: 1.0
|
||||
shutdown_delay: 10.0
|
||||
|
||||
size:
|
||||
width: 800
|
||||
height: 600
|
||||
resolutions:
|
||||
- 640x480
|
||||
- 800x600
|
||||
- 1024x768
|
||||
|
||||
cmd:
|
||||
- "/usr/bin/mjpg_streamer"
|
||||
- "-i"
|
||||
- "input_uvc.so -d /dev/kvmd-streamer -e 2 -y -n -r {width}x{height}"
|
||||
- "input_uvc.so -d /dev/kvmd-streamer -e 2 -y -n -r {resolution}"
|
||||
- "-o"
|
||||
- "output_http.so -l 0.0.0.0 -p 8082"
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ div.ctl-dropdown-content div.buttons-row {
|
||||
padding: 0;
|
||||
font-size: 0;
|
||||
}
|
||||
div.ctl-dropdown-content button {
|
||||
div.ctl-dropdown-content button, select {
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
color: var(--fg-color-normal);
|
||||
@ -105,26 +105,48 @@ div.ctl-dropdown-content button {
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
div.ctl-dropdown-content button:enabled:hover {
|
||||
div.ctl-dropdown-content button:enabled:hover, select:enabled:hover {
|
||||
color: var(--fg-color-intensive);
|
||||
background-color: var(--bg-color-dark) !important;
|
||||
}
|
||||
div.ctl-dropdown-content button:disabled {
|
||||
div.ctl-dropdown-content button:disabled, select:disabled {
|
||||
color: var(--fg-color-inactive);
|
||||
cursor: default;
|
||||
}
|
||||
div.ctl-dropdown-content button:active {
|
||||
div.ctl-dropdown-content button:active, select:active {
|
||||
color: var(--fg-color-selected) !important;
|
||||
}
|
||||
div.ctl-dropdown-content button.row50 {
|
||||
div.ctl-dropdown-content select {
|
||||
-webkit-appearance: button;
|
||||
-moz-appearance: button;
|
||||
appearance: button;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
background-image: url("../svg/select-arrow-normal.svg");
|
||||
background-position: center right;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
div.ctl-dropdown-content select:enabled:hover {
|
||||
background-image: url("../svg/select-arrow-intensive.svg") !important;
|
||||
}
|
||||
div.ctl-dropdown-content select:disabled {
|
||||
background-image: url("../svg/select-arrow-inactive.svg") !important;
|
||||
}
|
||||
div.ctl-dropdown-content select:active {
|
||||
color: var(--fg-color-intensive) !important;
|
||||
background-color: var(--bg-color-dark) !important;
|
||||
background-image: url("../svg/select-arrow-intensive.svg") !important;
|
||||
}
|
||||
div.ctl-dropdown-content .row50 {
|
||||
display: inline-block;
|
||||
width: 50%;
|
||||
}
|
||||
div.ctl-dropdown-content button.row25 {
|
||||
div.ctl-dropdown-content .row25 {
|
||||
display: inline-block;
|
||||
width: 25%;
|
||||
}
|
||||
div.ctl-dropdown-content button.row50:not(:first-child), button.row25:not(:first-child) {
|
||||
div.ctl-dropdown-content .row50:not(:first-child), .row25:not(:first-child) {
|
||||
border-left: var(--dark-border);
|
||||
}
|
||||
div.ctl-dropdown-content hr {
|
||||
|
||||
@ -35,21 +35,26 @@ div.stream-box-mouse-enabled {
|
||||
cursor: url("../svg/stream-mouse-cursor.svg"), pointer;
|
||||
}
|
||||
|
||||
div#stream-size {
|
||||
div.stream-params {
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
user-select: text;
|
||||
font-size: 12px;
|
||||
margin: 5px 15px 5px 15px;
|
||||
}
|
||||
div#stream-size span#stream-size-counter {
|
||||
|
||||
div.stream-params select#stream-resolution-select {
|
||||
margin: 8px 0 8px 0;
|
||||
}
|
||||
div#stream-size div#stream-size-slider-box {
|
||||
|
||||
div.stream-params span#stream-size-value {
|
||||
}
|
||||
div.stream-params div#stream-size-slider-box {
|
||||
margin-top: 5px;
|
||||
display: flex;
|
||||
}
|
||||
@supports (-webkit-appearance:none) {
|
||||
div#stream-size div#stream-size-slider-box input[type=range] {
|
||||
div.stream-params div#stream-size-slider-box input[type=range] {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
width: 100%;
|
||||
@ -60,7 +65,7 @@ div#stream-size div#stream-size-slider-box {
|
||||
}
|
||||
}
|
||||
@supports not (-webkit-appearance:none) {
|
||||
div#stream-size div#stream-size-slider-box input[type=range] {
|
||||
div.stream-params div#stream-size-slider-box input[type=range] {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
width: 100%;
|
||||
@ -69,12 +74,12 @@ div#stream-size div#stream-size-slider-box {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
div#stream-size div#stream-size-slider-box input[type=range]::-webkit-slider-runnable-track {
|
||||
div.stream-params div#stream-size-slider-box input[type=range]::-webkit-slider-runnable-track {
|
||||
height: 5px;
|
||||
background: var(--bg-color-light);
|
||||
border-radius: 3px;
|
||||
}
|
||||
div#stream-size div#stream-size-slider-box input[type=range]::-webkit-slider-thumb {
|
||||
div.stream-params div#stream-size-slider-box input[type=range]::-webkit-slider-thumb {
|
||||
border: var(--intensive-border);
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
@ -83,12 +88,12 @@ div#stream-size div#stream-size-slider-box input[type=range]::-webkit-slider-thu
|
||||
-webkit-appearance: none;
|
||||
margin-top: -7px;
|
||||
}
|
||||
div#stream-size div#stream-size-slider-box input[type=range]::-moz-range-track {
|
||||
div.stream-params div#stream-size-slider-box input[type=range]::-moz-range-track {
|
||||
height: 5px;
|
||||
background: var(--bg-color-light);
|
||||
border-radius: 3px;
|
||||
}
|
||||
div#stream-size div#stream-size-slider-box input[type=range]::-moz-range-thumb {
|
||||
div.stream-params div#stream-size-slider-box input[type=range]::-moz-range-thumb {
|
||||
border: var(--intensive-border);
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
|
||||
@ -70,8 +70,15 @@
|
||||
<button id="show-stream-button">• Show stream</button>
|
||||
<button disabled id="stream-reset-button">• Reset stream</button>
|
||||
<hr>
|
||||
<div data-dont-hide-menu id="stream-size">
|
||||
Stream size: <span id="stream-size-counter">100%</span>
|
||||
<div data-dont-hide-menu class="stream-params">
|
||||
Resolution:
|
||||
<select disabled data-dont-hide-menu id="stream-resolution-select">
|
||||
<option>640x480</option>
|
||||
</select>
|
||||
</div>
|
||||
<hr>
|
||||
<div data-dont-hide-menu class="stream-params">
|
||||
Stream size: <span id="stream-size-value">100%</span>
|
||||
<div id="stream-size-slider-box">
|
||||
<input id="stream-size-slider" type="range" min="50" max="150" value="100" step="10" />
|
||||
</div>
|
||||
|
||||
@ -4,6 +4,10 @@ function Stream(ui) {
|
||||
/********************************************************************************/
|
||||
|
||||
var __prev_state = false;
|
||||
|
||||
var __resolution = "640x480";
|
||||
var __resolutions = ["640x480"];
|
||||
|
||||
var __normal_size = {width: 640, height: 480};
|
||||
var __size_factor = 1;
|
||||
|
||||
@ -11,6 +15,7 @@ function Stream(ui) {
|
||||
$("stream-led").title = "Stream inactive";
|
||||
|
||||
$("stream-reset-button").onclick = __clickResetButton;
|
||||
$("stream-resolution-select").onchange = __changeResolution;
|
||||
$("stream-size-slider").oninput = __resize;
|
||||
$("stream-size-slider").onchange = __resize;
|
||||
|
||||
@ -19,6 +24,8 @@ function Stream(ui) {
|
||||
|
||||
/********************************************************************************/
|
||||
|
||||
// XXX: In current implementation we don't need this event because Stream() has own state poller
|
||||
|
||||
var __startPoller = function() {
|
||||
var http = tools.makeRequest("GET", "/streamer/?action=snapshot", function() {
|
||||
if (http.readyState === 2 || http.readyState === 4) {
|
||||
@ -33,6 +40,7 @@ function Stream(ui) {
|
||||
$("stream-led").className = "led-off";
|
||||
$("stream-led").title = "Stream inactive";
|
||||
$("stream-reset-button").disabled = true;
|
||||
$("stream-resolution-select").disabled = true;
|
||||
} else if (!__prev_state) {
|
||||
__refreshImage();
|
||||
__prev_state = true;
|
||||
@ -44,7 +52,7 @@ function Stream(ui) {
|
||||
}
|
||||
}
|
||||
});
|
||||
setTimeout(__startPoller, 2000);
|
||||
setTimeout(__startPoller, 1500);
|
||||
};
|
||||
|
||||
var __clickResetButton = function() {
|
||||
@ -58,9 +66,23 @@ function Stream(ui) {
|
||||
});
|
||||
};
|
||||
|
||||
var __changeResolution = function() {
|
||||
var resolution = $("stream-resolution-select").value;
|
||||
if (__resolution != resolution) {
|
||||
$("stream-resolution-select").disabled = true;
|
||||
var http = tools.makeRequest("POST", "/kvmd/streamer/set_params?resolution=" + resolution, function() {
|
||||
if (http.readyState === 4) {
|
||||
if (http.status !== 200) {
|
||||
alert("Can't change stream:", http.responseText);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var __resize = function() {
|
||||
var percent = $("stream-size-slider").value;
|
||||
$("stream-size-counter").innerHTML = percent + "%";
|
||||
$("stream-size-value").innerHTML = percent + "%";
|
||||
__size_factor = percent / 100;
|
||||
__applySizeFactor();
|
||||
};
|
||||
@ -75,7 +97,25 @@ function Stream(ui) {
|
||||
var __refreshImage = function() {
|
||||
var http = tools.makeRequest("GET", "/kvmd/streamer", function() {
|
||||
if (http.readyState === 4 && http.status === 200) {
|
||||
__normal_size = JSON.parse(http.responseText).result.size;
|
||||
var result = JSON.parse(http.responseText).result;
|
||||
|
||||
if (__resolutions != result.resolutions) {
|
||||
tools.info("Resolutions list changed:", result.resolutions);
|
||||
$("stream-resolution-select").innerHTML = "";
|
||||
result.resolutions.forEach(function(resolution) {
|
||||
$("stream-resolution-select").innerHTML += "<option value=\"" + resolution + "\">" + resolution + "</option>";
|
||||
});
|
||||
$("stream-resolution-select").disabled = (result.resolutions.length == 1);
|
||||
__resolutions = result.resolutions;
|
||||
}
|
||||
|
||||
if (__resolution != result.resolution) {
|
||||
tools.info("Resolution changed:", result.resolution);
|
||||
document.querySelector("#stream-resolution-select [value=\"" + result.resolution + "\"]").selected = true;
|
||||
__resolution = result.resolution;
|
||||
}
|
||||
|
||||
__normal_size = result.size;
|
||||
__applySizeFactor();
|
||||
$("stream-image").src = "/streamer/?action=stream&time=" + new Date().getTime();
|
||||
}
|
||||
|
||||
78
kvmd/web/svg/select-arrow-inactive.svg
Normal file
78
kvmd/web/svg/select-arrow-inactive.svg
Normal file
@ -0,0 +1,78 @@
|
||||
<?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="24"
|
||||
height="31.999998"
|
||||
viewBox="0 0 6.3500001 8.4666662"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||
sodipodi:docname="select-arrow-inactive.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.2"
|
||||
inkscape:cx="27.151934"
|
||||
inkscape:cy="16.615415"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1020"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
units="px" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<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:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-8.8745959,-36.821965)">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="opacity:1;fill:#6c7481;fill-opacity:1;stroke:none;stroke-width:2.64583325;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:75.59055328;stroke-opacity:1;paint-order:normal"
|
||||
id="path4749"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="12.049596"
|
||||
sodipodi:cy="40.702518"
|
||||
sodipodi:r1="1.411111"
|
||||
sodipodi:r2="0.70555568"
|
||||
sodipodi:arg1="1.5707963"
|
||||
sodipodi:arg2="2.6179939"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 12.049596,42.113629 -0.611029,-1.058333 -0.611029,-1.058333 1.222058,0 1.222058,0 -0.611029,1.058333 z"
|
||||
inkscape:transform-center-y="0.3527758" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
78
kvmd/web/svg/select-arrow-intensive.svg
Normal file
78
kvmd/web/svg/select-arrow-intensive.svg
Normal file
@ -0,0 +1,78 @@
|
||||
<?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="24"
|
||||
height="31.999998"
|
||||
viewBox="0 0 6.3500001 8.4666662"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||
sodipodi:docname="select-arrow-intensive.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.2"
|
||||
inkscape:cx="27.151934"
|
||||
inkscape:cy="16.615415"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1020"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
units="px" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<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:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-8.8745959,-36.821965)">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.64583325;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:75.59055328;stroke-opacity:1;paint-order:normal"
|
||||
id="path4749"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="12.049596"
|
||||
sodipodi:cy="40.702518"
|
||||
sodipodi:r1="1.411111"
|
||||
sodipodi:r2="0.70555568"
|
||||
sodipodi:arg1="1.5707963"
|
||||
sodipodi:arg2="2.6179939"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 12.049596,42.113629 -0.611029,-1.058333 -0.611029,-1.058333 1.222058,0 1.222058,0 -0.611029,1.058333 z"
|
||||
inkscape:transform-center-y="0.3527758" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
78
kvmd/web/svg/select-arrow-normal.svg
Normal file
78
kvmd/web/svg/select-arrow-normal.svg
Normal file
@ -0,0 +1,78 @@
|
||||
<?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="24"
|
||||
height="31.999998"
|
||||
viewBox="0 0 6.3500001 8.4666662"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||
sodipodi:docname="select-arrow-normal.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.2"
|
||||
inkscape:cx="27.151934"
|
||||
inkscape:cy="16.615415"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1020"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
units="px" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<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:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-8.8745959,-36.821965)">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="opacity:1;fill:#c3c3c3;fill-opacity:1;stroke:none;stroke-width:2.64583325;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:75.59055328;stroke-opacity:1;paint-order:normal"
|
||||
id="path4749"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="12.049596"
|
||||
sodipodi:cy="40.702518"
|
||||
sodipodi:r1="1.411111"
|
||||
sodipodi:r2="0.70555568"
|
||||
sodipodi:arg1="1.5707963"
|
||||
sodipodi:arg2="2.6179939"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 12.049596,42.113629 -0.611029,-1.058333 -0.611029,-1.058333 1.222058,0 1.222058,0 -0.611029,1.058333 z"
|
||||
inkscape:transform-center-y="0.3527758" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
Loading…
x
Reference in New Issue
Block a user