Merge pull request #11812 from german77/save_capture
service: caps: Implement SaveScreenShotEx0 and variants
This commit is contained in:
commit
6eb3a583cb
11 changed files with 2225 additions and 14 deletions
2
externals/CMakeLists.txt
vendored
2
externals/CMakeLists.txt
vendored
|
@ -168,7 +168,7 @@ if (NOT TARGET LLVM::Demangle)
|
||||||
add_library(LLVM::Demangle ALIAS demangle)
|
add_library(LLVM::Demangle ALIAS demangle)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(stb stb/stb_dxt.cpp stb/stb_image.cpp stb/stb_image_resize.cpp)
|
add_library(stb stb/stb_dxt.cpp stb/stb_image.cpp stb/stb_image_resize.cpp stb/stb_image_write.cpp)
|
||||||
target_include_directories(stb PUBLIC ./stb)
|
target_include_directories(stb PUBLIC ./stb)
|
||||||
|
|
||||||
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
|
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
|
||||||
|
|
1677
externals/stb/stb_image_write.cpp
vendored
Normal file
1677
externals/stb/stb_image_write.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
297
externals/stb/stb_image_write.h
vendored
Normal file
297
externals/stb/stb_image_write.h
vendored
Normal file
|
@ -0,0 +1,297 @@
|
||||||
|
// SPDX-FileCopyrightText: stb http://nothings.org/stb
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
/* stb_image_write - v1.16 - public domain - http://nothings.org/stb
|
||||||
|
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
|
||||||
|
no warranty implied; use at your own risk
|
||||||
|
|
||||||
|
Before #including,
|
||||||
|
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
|
||||||
|
in the file that you want to have the implementation.
|
||||||
|
|
||||||
|
Will probably not work correctly with strict-aliasing optimizations.
|
||||||
|
|
||||||
|
ABOUT:
|
||||||
|
|
||||||
|
This header file is a library for writing images to C stdio or a callback.
|
||||||
|
|
||||||
|
The PNG output is not optimal; it is 20-50% larger than the file
|
||||||
|
written by a decent optimizing implementation; though providing a custom
|
||||||
|
zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
|
||||||
|
This library is designed for source code compactness and simplicity,
|
||||||
|
not optimal image file size or run-time performance.
|
||||||
|
|
||||||
|
BUILDING:
|
||||||
|
|
||||||
|
You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
|
||||||
|
You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
|
||||||
|
malloc,realloc,free.
|
||||||
|
You can #define STBIW_MEMMOVE() to replace memmove()
|
||||||
|
You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
|
||||||
|
for PNG compression (instead of the builtin one), it must have the following signature:
|
||||||
|
unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
|
||||||
|
The returned data will be freed with STBIW_FREE() (free() by default),
|
||||||
|
so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
|
||||||
|
|
||||||
|
UNICODE:
|
||||||
|
|
||||||
|
If compiling for Windows and you wish to use Unicode filenames, compile
|
||||||
|
with
|
||||||
|
#define STBIW_WINDOWS_UTF8
|
||||||
|
and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert
|
||||||
|
Windows wchar_t filenames to utf8.
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
|
||||||
|
There are five functions, one for each image file format:
|
||||||
|
|
||||||
|
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||||
|
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||||
|
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||||
|
int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);
|
||||||
|
int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||||
|
|
||||||
|
void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
|
||||||
|
|
||||||
|
There are also five equivalent functions that use an arbitrary write function. You are
|
||||||
|
expected to open/close your file-equivalent before and after calling these:
|
||||||
|
|
||||||
|
int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||||
|
int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||||
|
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||||
|
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
|
||||||
|
int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
|
||||||
|
|
||||||
|
where the callback is:
|
||||||
|
void stbi_write_func(void *context, void *data, int size);
|
||||||
|
|
||||||
|
You can configure it with these global variables:
|
||||||
|
int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
|
||||||
|
int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
|
||||||
|
int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
|
||||||
|
|
||||||
|
|
||||||
|
You can define STBI_WRITE_NO_STDIO to disable the file variant of these
|
||||||
|
functions, so the library will not use stdio.h at all. However, this will
|
||||||
|
also disable HDR writing, because it requires stdio for formatted output.
|
||||||
|
|
||||||
|
Each function returns 0 on failure and non-0 on success.
|
||||||
|
|
||||||
|
The functions create an image file defined by the parameters. The image
|
||||||
|
is a rectangle of pixels stored from left-to-right, top-to-bottom.
|
||||||
|
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
|
||||||
|
per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
|
||||||
|
monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
|
||||||
|
The *data pointer points to the first byte of the top-left-most pixel.
|
||||||
|
For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
|
||||||
|
a row of pixels to the first byte of the next row of pixels.
|
||||||
|
|
||||||
|
PNG creates output files with the same number of components as the input.
|
||||||
|
The BMP format expands Y to RGB in the file format and does not
|
||||||
|
output alpha.
|
||||||
|
|
||||||
|
PNG supports writing rectangles of data even when the bytes storing rows of
|
||||||
|
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
|
||||||
|
by supplying the stride between the beginning of adjacent rows. The other
|
||||||
|
formats do not. (Thus you cannot write a native-format BMP through the BMP
|
||||||
|
writer, both because it is in BGR order and because it may have padding
|
||||||
|
at the end of the line.)
|
||||||
|
|
||||||
|
PNG allows you to set the deflate compression level by setting the global
|
||||||
|
variable 'stbi_write_png_compression_level' (it defaults to 8).
|
||||||
|
|
||||||
|
HDR expects linear float data. Since the format is always 32-bit rgb(e)
|
||||||
|
data, alpha (if provided) is discarded, and for monochrome data it is
|
||||||
|
replicated across all three channels.
|
||||||
|
|
||||||
|
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
|
||||||
|
data, set the global variable 'stbi_write_tga_with_rle' to 0.
|
||||||
|
|
||||||
|
JPEG does ignore alpha channels in input data; quality is between 1 and 100.
|
||||||
|
Higher quality looks better but results in a bigger image.
|
||||||
|
JPEG baseline (no JPEG progressive).
|
||||||
|
|
||||||
|
CREDITS:
|
||||||
|
|
||||||
|
|
||||||
|
Sean Barrett - PNG/BMP/TGA
|
||||||
|
Baldur Karlsson - HDR
|
||||||
|
Jean-Sebastien Guay - TGA monochrome
|
||||||
|
Tim Kelsey - misc enhancements
|
||||||
|
Alan Hickman - TGA RLE
|
||||||
|
Emmanuel Julien - initial file IO callback implementation
|
||||||
|
Jon Olick - original jo_jpeg.cpp code
|
||||||
|
Daniel Gibson - integrate JPEG, allow external zlib
|
||||||
|
Aarni Koskela - allow choosing PNG filter
|
||||||
|
|
||||||
|
bugfixes:
|
||||||
|
github:Chribba
|
||||||
|
Guillaume Chereau
|
||||||
|
github:jry2
|
||||||
|
github:romigrou
|
||||||
|
Sergio Gonzalez
|
||||||
|
Jonas Karlsson
|
||||||
|
Filip Wasil
|
||||||
|
Thatcher Ulrich
|
||||||
|
github:poppolopoppo
|
||||||
|
Patrick Boettcher
|
||||||
|
github:xeekworx
|
||||||
|
Cap Petschulat
|
||||||
|
Simon Rodriguez
|
||||||
|
Ivan Tikhonov
|
||||||
|
github:ignotion
|
||||||
|
Adam Schackart
|
||||||
|
Andrew Kensler
|
||||||
|
|
||||||
|
LICENSE
|
||||||
|
|
||||||
|
See end of file for license information.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_STB_IMAGE_WRITE_H
|
||||||
|
#define INCLUDE_STB_IMAGE_WRITE_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'
|
||||||
|
#ifndef STBIWDEF
|
||||||
|
#ifdef STB_IMAGE_WRITE_STATIC
|
||||||
|
#define STBIWDEF static
|
||||||
|
#else
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define STBIWDEF extern "C"
|
||||||
|
#else
|
||||||
|
#define STBIWDEF extern
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
|
||||||
|
STBIWDEF int stbi_write_tga_with_rle;
|
||||||
|
STBIWDEF int stbi_write_png_compression_level;
|
||||||
|
STBIWDEF int stbi_write_force_png_filter;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STBI_WRITE_NO_STDIO
|
||||||
|
STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||||
|
STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||||
|
STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||||
|
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||||
|
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
|
||||||
|
|
||||||
|
#ifdef STBIW_WINDOWS_UTF8
|
||||||
|
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void stbi_write_func(void *context, void *data, int size);
|
||||||
|
|
||||||
|
STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||||
|
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||||
|
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||||
|
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
|
||||||
|
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
|
||||||
|
STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len);
|
||||||
|
|
||||||
|
STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
|
||||||
|
|
||||||
|
#endif//INCLUDE_STB_IMAGE_WRITE_H
|
||||||
|
|
||||||
|
/* Revision history
|
||||||
|
1.16 (2021-07-11)
|
||||||
|
make Deflate code emit uncompressed blocks when it would otherwise expand
|
||||||
|
support writing BMPs with alpha channel
|
||||||
|
1.15 (2020-07-13) unknown
|
||||||
|
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
|
||||||
|
1.13
|
||||||
|
1.12
|
||||||
|
1.11 (2019-08-11)
|
||||||
|
|
||||||
|
1.10 (2019-02-07)
|
||||||
|
support utf8 filenames in Windows; fix warnings and platform ifdefs
|
||||||
|
1.09 (2018-02-11)
|
||||||
|
fix typo in zlib quality API, improve STB_I_W_STATIC in C++
|
||||||
|
1.08 (2018-01-29)
|
||||||
|
add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
|
||||||
|
1.07 (2017-07-24)
|
||||||
|
doc fix
|
||||||
|
1.06 (2017-07-23)
|
||||||
|
writing JPEG (using Jon Olick's code)
|
||||||
|
1.05 ???
|
||||||
|
1.04 (2017-03-03)
|
||||||
|
monochrome BMP expansion
|
||||||
|
1.03 ???
|
||||||
|
1.02 (2016-04-02)
|
||||||
|
avoid allocating large structures on the stack
|
||||||
|
1.01 (2016-01-16)
|
||||||
|
STBIW_REALLOC_SIZED: support allocators with no realloc support
|
||||||
|
avoid race-condition in crc initialization
|
||||||
|
minor compile issues
|
||||||
|
1.00 (2015-09-14)
|
||||||
|
installable file IO function
|
||||||
|
0.99 (2015-09-13)
|
||||||
|
warning fixes; TGA rle support
|
||||||
|
0.98 (2015-04-08)
|
||||||
|
added STBIW_MALLOC, STBIW_ASSERT etc
|
||||||
|
0.97 (2015-01-18)
|
||||||
|
fixed HDR asserts, rewrote HDR rle logic
|
||||||
|
0.96 (2015-01-17)
|
||||||
|
add HDR output
|
||||||
|
fix monochrome BMP
|
||||||
|
0.95 (2014-08-17)
|
||||||
|
add monochrome TGA output
|
||||||
|
0.94 (2014-05-31)
|
||||||
|
rename private functions to avoid conflicts with stb_image.h
|
||||||
|
0.93 (2014-05-27)
|
||||||
|
warning fixes
|
||||||
|
0.92 (2010-08-01)
|
||||||
|
casts to unsigned char to fix warnings
|
||||||
|
0.91 (2010-07-17)
|
||||||
|
first public release
|
||||||
|
0.90 first internal release
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE A - MIT License
|
||||||
|
Copyright (c) 2017 Sean Barrett
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
commercial or non-commercial, and by any means.
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||||
|
software dedicate any and all copyright interest in the software to the public
|
||||||
|
domain. We make this dedication for the benefit of the public at large and to
|
||||||
|
the detriment of our heirs and successors. We intend this dedication to be an
|
||||||
|
overt act of relinquishment in perpetuity of all present and future rights to
|
||||||
|
this software under copyright law.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*/
|
|
@ -25,11 +25,12 @@ void LoopProcess(Core::System& system) {
|
||||||
server_manager->RegisterNamedService(
|
server_manager->RegisterNamedService(
|
||||||
"caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager));
|
"caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager));
|
||||||
|
|
||||||
server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system));
|
server_manager->RegisterNamedService(
|
||||||
|
"caps:ss", std::make_shared<IScreenShotService>(system, album_manager));
|
||||||
server_manager->RegisterNamedService("caps:sc",
|
server_manager->RegisterNamedService("caps:sc",
|
||||||
std::make_shared<IScreenShotControlService>(system));
|
std::make_shared<IScreenShotControlService>(system));
|
||||||
server_manager->RegisterNamedService("caps:su",
|
server_manager->RegisterNamedService(
|
||||||
std::make_shared<IScreenShotApplicationService>(system));
|
"caps:su", std::make_shared<IScreenShotApplicationService>(system, album_manager));
|
||||||
|
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
#include <stb_image_resize.h>
|
#include <stb_image_resize.h>
|
||||||
|
#include <stb_image_write.h>
|
||||||
|
|
||||||
#include "common/fs/file.h"
|
#include "common/fs/file.h"
|
||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
|
@ -227,6 +228,49 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail(
|
||||||
+static_cast<int>(out_image_output.height), decoder_options.flags);
|
+static_cast<int>(out_image_output.height), decoder_options.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
||||||
|
const ScreenShotAttribute& attribute,
|
||||||
|
std::span<const u8> image_data, u64 aruid) {
|
||||||
|
return SaveScreenShot(out_entry, attribute, {}, image_data, aruid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
||||||
|
const ScreenShotAttribute& attribute,
|
||||||
|
const ApplicationData& app_data, std::span<const u8> image_data,
|
||||||
|
u64 aruid) {
|
||||||
|
const u64 title_id = system.GetApplicationProcessProgramID();
|
||||||
|
const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
|
||||||
|
|
||||||
|
s64 posix_time{};
|
||||||
|
Result result = user_clock.GetCurrentTime(system, posix_time);
|
||||||
|
|
||||||
|
if (result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto date = ConvertToAlbumDateTime(posix_time);
|
||||||
|
|
||||||
|
return SaveImage(out_entry, image_data, title_id, date);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
|
||||||
|
const ScreenShotAttribute& attribute,
|
||||||
|
const AlbumFileId& file_id,
|
||||||
|
std::span<const u8> image_data) {
|
||||||
|
const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
|
||||||
|
|
||||||
|
s64 posix_time{};
|
||||||
|
Result result = user_clock.GetCurrentTime(system, posix_time);
|
||||||
|
|
||||||
|
if (result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto date = ConvertToAlbumDateTime(posix_time);
|
||||||
|
|
||||||
|
return SaveImage(out_entry, image_data, file_id.application_id, date);
|
||||||
|
}
|
||||||
|
|
||||||
Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const {
|
Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const {
|
||||||
const auto file = album_files.find(file_id);
|
const auto file = album_files.find(file_id);
|
||||||
|
|
||||||
|
@ -365,6 +409,45 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image,
|
||||||
|
u64 title_id, const AlbumFileDateTime& date) const {
|
||||||
|
const auto screenshot_path =
|
||||||
|
Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir);
|
||||||
|
const std::string formatted_date =
|
||||||
|
fmt::format("{:04}-{:02}-{:02}_{:02}-{:02}-{:02}-{:03}", date.year, date.month, date.day,
|
||||||
|
date.hour, date.minute, date.second, 0);
|
||||||
|
const std::string file_path =
|
||||||
|
fmt::format("{}/{:016x}_{}.png", screenshot_path, title_id, formatted_date);
|
||||||
|
|
||||||
|
const Common::FS::IOFile db_file{file_path, Common::FS::FileAccessMode::Write,
|
||||||
|
Common::FS::FileType::BinaryFile};
|
||||||
|
|
||||||
|
s32 len;
|
||||||
|
const u8* png = stbi_write_png_to_mem(image.data(), 0, 1280, 720, STBI_rgb_alpha, &len);
|
||||||
|
|
||||||
|
if (!png) {
|
||||||
|
return ResultFileCountLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> png_image(len);
|
||||||
|
std::memcpy(png_image.data(), png, len);
|
||||||
|
|
||||||
|
if (db_file.Write(png_image) != png_image.size()) {
|
||||||
|
return ResultFileCountLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_entry = {
|
||||||
|
.size = png_image.size(),
|
||||||
|
.hash = {},
|
||||||
|
.datetime = date,
|
||||||
|
.storage = AlbumStorage::Sd,
|
||||||
|
.content = ContentType::Screenshot,
|
||||||
|
.unknown = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
|
AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
|
||||||
Time::TimeZone::CalendarInfo calendar_date{};
|
Time::TimeZone::CalendarInfo calendar_date{};
|
||||||
const auto& time_zone_manager =
|
const auto& time_zone_manager =
|
||||||
|
|
|
@ -58,6 +58,15 @@ public:
|
||||||
std::vector<u8>& out_image, const AlbumFileId& file_id,
|
std::vector<u8>& out_image, const AlbumFileId& file_id,
|
||||||
const ScreenShotDecodeOption& decoder_options) const;
|
const ScreenShotDecodeOption& decoder_options) const;
|
||||||
|
|
||||||
|
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
|
||||||
|
std::span<const u8> image_data, u64 aruid);
|
||||||
|
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
|
||||||
|
const ApplicationData& app_data, std::span<const u8> image_data,
|
||||||
|
u64 aruid);
|
||||||
|
Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
|
||||||
|
const ScreenShotAttribute& attribute, const AlbumFileId& file_id,
|
||||||
|
std::span<const u8> image_data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr std::size_t NandAlbumFileLimit = 1000;
|
static constexpr std::size_t NandAlbumFileLimit = 1000;
|
||||||
static constexpr std::size_t SdAlbumFileLimit = 10000;
|
static constexpr std::size_t SdAlbumFileLimit = 10000;
|
||||||
|
@ -67,6 +76,8 @@ private:
|
||||||
Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const;
|
Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const;
|
||||||
Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
|
Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
|
||||||
int height, ScreenShotDecoderFlag flag) const;
|
int height, ScreenShotDecoderFlag flag) const;
|
||||||
|
Result SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image, u64 title_id,
|
||||||
|
const AlbumFileDateTime& date) const;
|
||||||
|
|
||||||
AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const;
|
AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const;
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,25 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/hle/service/caps/caps_manager.h"
|
||||||
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
#include "core/hle/service/caps/caps_ss.h"
|
#include "core/hle/service/caps/caps_ss.h"
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
|
||||||
IScreenShotService::IScreenShotService(Core::System& system_)
|
IScreenShotService::IScreenShotService(Core::System& system_,
|
||||||
: ServiceFramework{system_, "caps:ss"} {
|
std::shared_ptr<AlbumManager> album_manager)
|
||||||
|
: ServiceFramework{system_, "caps:ss"}, manager{album_manager} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{201, nullptr, "SaveScreenShot"},
|
{201, nullptr, "SaveScreenShot"},
|
||||||
{202, nullptr, "SaveEditedScreenShot"},
|
{202, nullptr, "SaveEditedScreenShot"},
|
||||||
{203, nullptr, "SaveScreenShotEx0"},
|
{203, &IScreenShotService::SaveScreenShotEx0, "SaveScreenShotEx0"},
|
||||||
{204, nullptr, "SaveEditedScreenShotEx0"},
|
{204, nullptr, "SaveEditedScreenShotEx0"},
|
||||||
{206, nullptr, "Unknown206"},
|
{206, &IScreenShotService::SaveEditedScreenShotEx1, "SaveEditedScreenShotEx1"},
|
||||||
{208, nullptr, "SaveScreenShotOfMovieEx1"},
|
{208, nullptr, "SaveScreenShotOfMovieEx1"},
|
||||||
{1000, nullptr, "Unknown1000"},
|
{1000, nullptr, "Unknown1000"},
|
||||||
};
|
};
|
||||||
|
@ -24,4 +30,65 @@ IScreenShotService::IScreenShotService(Core::System& system_)
|
||||||
|
|
||||||
IScreenShotService::~IScreenShotService() = default;
|
IScreenShotService::~IScreenShotService() = default;
|
||||||
|
|
||||||
|
void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
struct Parameters {
|
||||||
|
ScreenShotAttribute attribute{};
|
||||||
|
u32 report_option{};
|
||||||
|
INSERT_PADDING_BYTES(0x4);
|
||||||
|
u64 applet_resource_user_id{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
|
||||||
|
|
||||||
|
const auto parameters{rp.PopRaw<Parameters>()};
|
||||||
|
const auto image_data_buffer = ctx.ReadBuffer();
|
||||||
|
|
||||||
|
LOG_INFO(Service_Capture,
|
||||||
|
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
||||||
|
parameters.report_option, image_data_buffer.size(),
|
||||||
|
parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
ApplicationAlbumEntry entry{};
|
||||||
|
const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer,
|
||||||
|
parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 10};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushRaw(entry);
|
||||||
|
}
|
||||||
|
void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
struct Parameters {
|
||||||
|
ScreenShotAttribute attribute;
|
||||||
|
u64 width;
|
||||||
|
u64 height;
|
||||||
|
u64 thumbnail_width;
|
||||||
|
u64 thumbnail_height;
|
||||||
|
AlbumFileId file_id;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 0x78, "Parameters has incorrect size.");
|
||||||
|
|
||||||
|
const auto parameters{rp.PopRaw<Parameters>()};
|
||||||
|
const auto application_data_buffer = ctx.ReadBuffer(0);
|
||||||
|
const auto image_data_buffer = ctx.ReadBuffer(1);
|
||||||
|
const auto thumbnail_image_data_buffer = ctx.ReadBuffer(2);
|
||||||
|
|
||||||
|
LOG_INFO(Service_Capture,
|
||||||
|
"called, width={}, height={}, thumbnail_width={}, thumbnail_height={}, "
|
||||||
|
"application_id={:016x}, storage={}, type={}, app_data_buffer_size={}, "
|
||||||
|
"image_data_buffer_size={}, thumbnail_image_buffer_size={}",
|
||||||
|
parameters.width, parameters.height, parameters.thumbnail_width,
|
||||||
|
parameters.thumbnail_height, parameters.file_id.application_id,
|
||||||
|
parameters.file_id.storage, parameters.file_id.type, application_data_buffer.size(),
|
||||||
|
image_data_buffer.size(), thumbnail_image_data_buffer.size());
|
||||||
|
|
||||||
|
ApplicationAlbumEntry entry{};
|
||||||
|
const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute,
|
||||||
|
parameters.file_id, image_data_buffer);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 10};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushRaw(entry);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Service::Capture
|
} // namespace Service::Capture
|
||||||
|
|
|
@ -13,8 +13,14 @@ namespace Service::Capture {
|
||||||
|
|
||||||
class IScreenShotService final : public ServiceFramework<IScreenShotService> {
|
class IScreenShotService final : public ServiceFramework<IScreenShotService> {
|
||||||
public:
|
public:
|
||||||
explicit IScreenShotService(Core::System& system_);
|
explicit IScreenShotService(Core::System& system_, std::shared_ptr<AlbumManager> album_manager);
|
||||||
~IScreenShotService() override;
|
~IScreenShotService() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SaveScreenShotEx0(HLERequestContext& ctx);
|
||||||
|
void SaveEditedScreenShotEx1(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
std::shared_ptr<AlbumManager> manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Capture
|
} // namespace Service::Capture
|
||||||
|
|
|
@ -2,19 +2,22 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/hle/service/caps/caps_manager.h"
|
||||||
#include "core/hle/service/caps/caps_su.h"
|
#include "core/hle/service/caps/caps_su.h"
|
||||||
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
|
||||||
IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_)
|
IScreenShotApplicationService::IScreenShotApplicationService(
|
||||||
: ServiceFramework{system_, "caps:su"} {
|
Core::System& system_, std::shared_ptr<AlbumManager> album_manager)
|
||||||
|
: ServiceFramework{system_, "caps:su"}, manager{album_manager} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
{32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||||
{201, nullptr, "SaveScreenShot"},
|
{201, nullptr, "SaveScreenShot"},
|
||||||
{203, nullptr, "SaveScreenShotEx0"},
|
{203, &IScreenShotApplicationService::SaveScreenShotEx0, "SaveScreenShotEx0"},
|
||||||
{205, nullptr, "SaveScreenShotEx1"},
|
{205, &IScreenShotApplicationService::SaveScreenShotEx1, "SaveScreenShotEx1"},
|
||||||
{210, nullptr, "SaveScreenShotEx2"},
|
{210, nullptr, "SaveScreenShotEx2"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -36,4 +39,62 @@ void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
struct Parameters {
|
||||||
|
ScreenShotAttribute attribute{};
|
||||||
|
AlbumReportOption report_option{};
|
||||||
|
INSERT_PADDING_BYTES(0x4);
|
||||||
|
u64 applet_resource_user_id{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
|
||||||
|
|
||||||
|
const auto parameters{rp.PopRaw<Parameters>()};
|
||||||
|
const auto image_data_buffer = ctx.ReadBuffer();
|
||||||
|
|
||||||
|
LOG_INFO(Service_Capture,
|
||||||
|
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
||||||
|
parameters.report_option, image_data_buffer.size(),
|
||||||
|
parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
ApplicationAlbumEntry entry{};
|
||||||
|
const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer,
|
||||||
|
parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 10};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushRaw(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
struct Parameters {
|
||||||
|
ScreenShotAttribute attribute{};
|
||||||
|
AlbumReportOption report_option{};
|
||||||
|
INSERT_PADDING_BYTES(0x4);
|
||||||
|
u64 applet_resource_user_id{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
|
||||||
|
|
||||||
|
const auto parameters{rp.PopRaw<Parameters>()};
|
||||||
|
const auto app_data_buffer = ctx.ReadBuffer(0);
|
||||||
|
const auto image_data_buffer = ctx.ReadBuffer(1);
|
||||||
|
|
||||||
|
LOG_INFO(Service_Capture,
|
||||||
|
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
|
||||||
|
parameters.report_option, image_data_buffer.size(),
|
||||||
|
parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
ApplicationAlbumEntry entry{};
|
||||||
|
ApplicationData app_data{};
|
||||||
|
std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData));
|
||||||
|
const auto result =
|
||||||
|
manager->SaveScreenShot(entry, parameters.attribute, app_data, image_data_buffer,
|
||||||
|
parameters.applet_resource_user_id);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 10};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushRaw(entry);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Service::Capture
|
} // namespace Service::Capture
|
||||||
|
|
|
@ -10,14 +10,20 @@ class System;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
class AlbumManager;
|
||||||
|
|
||||||
class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
|
class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
|
||||||
public:
|
public:
|
||||||
explicit IScreenShotApplicationService(Core::System& system_);
|
explicit IScreenShotApplicationService(Core::System& system_,
|
||||||
|
std::shared_ptr<AlbumManager> album_manager);
|
||||||
~IScreenShotApplicationService() override;
|
~IScreenShotApplicationService() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetShimLibraryVersion(HLERequestContext& ctx);
|
void SetShimLibraryVersion(HLERequestContext& ctx);
|
||||||
|
void SaveScreenShotEx0(HLERequestContext& ctx);
|
||||||
|
void SaveScreenShotEx1(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
std::shared_ptr<AlbumManager> manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Capture
|
} // namespace Service::Capture
|
||||||
|
|
|
@ -20,6 +20,8 @@ enum class AlbumImageOrientation {
|
||||||
enum class AlbumReportOption : s32 {
|
enum class AlbumReportOption : s32 {
|
||||||
Disable,
|
Disable,
|
||||||
Enable,
|
Enable,
|
||||||
|
Unknown2,
|
||||||
|
Unknown3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ContentType : u8 {
|
enum class ContentType : u8 {
|
||||||
|
|
Loading…
Reference in a new issue