mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 01:20:42 +00:00
Add processing to different formats and max size while fetching thumb
This commit is contained in:
@@ -648,8 +648,9 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_LogText(const char *text);
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_LogMessage(LogMessageType type,
|
||||
const char *project, const char *file,
|
||||
unsigned int line, const char *text);
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC RENDERDOC_GetThumbnail(const char *filename, byte *buf,
|
||||
uint32_t &len);
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC RENDERDOC_GetThumbnail(const char *filename,
|
||||
FileType type, uint32_t maxsize,
|
||||
rdctype::array<byte> *buf);
|
||||
extern "C" RENDERDOC_API const char *RENDERDOC_CC RENDERDOC_GetVersionString();
|
||||
extern "C" RENDERDOC_API const char *RENDERDOC_CC RENDERDOC_GetCommitHash();
|
||||
extern "C" RENDERDOC_API const char *RENDERDOC_CC RENDERDOC_GetConfigSetting(const char *name);
|
||||
|
||||
@@ -127,15 +127,12 @@ void RenderDoc::TargetControlClientThread(void *s)
|
||||
ser.Serialise("", captures.back().timestamp);
|
||||
ser.Serialise("", path);
|
||||
|
||||
uint32_t len = 0;
|
||||
RENDERDOC_GetThumbnail(captures.back().path.c_str(), NULL, len);
|
||||
byte *thumb = new byte[len];
|
||||
RENDERDOC_GetThumbnail(captures.back().path.c_str(), thumb, len);
|
||||
rdctype::array<byte> buf;
|
||||
RENDERDOC_GetThumbnail(captures.back().path.c_str(), eFileType_JPG, 0, &buf);
|
||||
|
||||
size_t l = len;
|
||||
ser.Serialise("", len);
|
||||
ser.SerialiseBuffer("", thumb, l);
|
||||
delete[] thumb;
|
||||
size_t sz = buf.size();
|
||||
ser.Serialise("", buf.count);
|
||||
ser.SerialiseBuffer("", buf.elems, sz);
|
||||
}
|
||||
else if(childprocs.size() != children.size())
|
||||
{
|
||||
@@ -596,7 +593,7 @@ public:
|
||||
msg->NewCapture.path = path;
|
||||
msg->NewCapture.local = m_Local;
|
||||
|
||||
uint32_t thumblen = 0;
|
||||
int32_t thumblen = 0;
|
||||
ser->Serialise("", thumblen);
|
||||
|
||||
create_array_uninit(msg->NewCapture.thumbnail, thumblen);
|
||||
|
||||
@@ -28,11 +28,15 @@
|
||||
#include "common/common.h"
|
||||
#include "core/core.h"
|
||||
#include "data/version.h"
|
||||
#include "jpeg-compressor/jpgd.h"
|
||||
#include "jpeg-compressor/jpge.h"
|
||||
#include "maths/camera.h"
|
||||
#include "maths/formatpacking.h"
|
||||
#include "replay/replay_renderer.h"
|
||||
#include "serialise/serialiser.h"
|
||||
#include "serialise/string_utils.h"
|
||||
#include "stb/stb_image_resize.h"
|
||||
#include "stb/stb_image_write.h"
|
||||
|
||||
// these entry points are for the replay/analysis side - not for the application.
|
||||
|
||||
@@ -420,8 +424,17 @@ extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_InjectIntoProcess(
|
||||
waitForExit != 0);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC RENDERDOC_GetThumbnail(const char *filename, byte *buf,
|
||||
uint32_t &len)
|
||||
static void writeToByteVector(void *context, void *data, int size)
|
||||
{
|
||||
std::vector<byte> *vec = (std::vector<byte> *)context;
|
||||
byte *start = (byte *)data;
|
||||
byte *end = start + size;
|
||||
vec->insert(vec->end(), start, end);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API bool32 RENDERDOC_CC RENDERDOC_GetThumbnail(const char *filename,
|
||||
FileType type, uint32_t maxsize,
|
||||
rdctype::array<byte> *buf)
|
||||
{
|
||||
Serialiser ser(filename, Serialiser::READING, false);
|
||||
|
||||
@@ -453,20 +466,97 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC RENDERDOC_GetThumbnail(const char *
|
||||
if(jpgbuf == NULL)
|
||||
return false;
|
||||
|
||||
if(buf == NULL)
|
||||
// if the desired output is jpg and either there's no max size or it's already satisfied,
|
||||
// return the data directly
|
||||
if(type == eFileType_JPG && (maxsize == 0 || (maxsize > thumbwidth && maxsize > thumbheight)))
|
||||
{
|
||||
len = (uint32_t)thumblen;
|
||||
delete[] jpgbuf;
|
||||
return true;
|
||||
create_array_init(*buf, thumblen, jpgbuf);
|
||||
}
|
||||
|
||||
if(thumblen > len)
|
||||
else
|
||||
{
|
||||
delete[] jpgbuf;
|
||||
return false;
|
||||
}
|
||||
// otherwise we need to decode, resample maybe, and re-encode
|
||||
|
||||
memcpy(buf, jpgbuf, thumblen);
|
||||
int w = (int)thumbwidth;
|
||||
int h = (int)thumbheight;
|
||||
int comp = 3;
|
||||
byte *thumbpixels =
|
||||
jpgd::decompress_jpeg_image_from_memory(jpgbuf, (int)thumblen, &w, &h, &comp, 3);
|
||||
|
||||
if(maxsize != 0)
|
||||
{
|
||||
uint32_t clampedWidth = RDCMIN(maxsize, thumbwidth);
|
||||
uint32_t clampedHeight = RDCMIN(maxsize, thumbheight);
|
||||
|
||||
if(clampedWidth != thumbwidth || clampedHeight != thumbheight)
|
||||
{
|
||||
// preserve aspect ratio, take the smallest scale factor and multiply both
|
||||
float scaleX = float(clampedWidth) / float(thumbwidth);
|
||||
float scaleY = float(clampedHeight) / float(thumbheight);
|
||||
|
||||
if(scaleX < scaleY)
|
||||
clampedHeight = uint32_t(scaleX * thumbheight);
|
||||
else if(scaleY < scaleX)
|
||||
clampedWidth = uint32_t(scaleY * thumbwidth);
|
||||
|
||||
byte *resizedpixels = (byte *)malloc(3 * clampedWidth * clampedHeight);
|
||||
|
||||
stbir_resize_uint8_srgb(thumbpixels, thumbwidth, thumbheight, 0, resizedpixels,
|
||||
clampedWidth, clampedHeight, 0, 3, -1, 0);
|
||||
|
||||
free(thumbpixels);
|
||||
|
||||
thumbpixels = resizedpixels;
|
||||
thumbwidth = clampedWidth;
|
||||
thumbheight = clampedHeight;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<byte> encodedBytes;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case eFileType_JPG:
|
||||
{
|
||||
int len = thumbwidth * thumbheight * 3;
|
||||
encodedBytes.resize(len);
|
||||
jpge::params p;
|
||||
p.m_quality = 90;
|
||||
jpge::compress_image_to_jpeg_file_in_memory(&encodedBytes[0], len, (int)thumbwidth,
|
||||
(int)thumbheight, 3, thumbpixels, p);
|
||||
encodedBytes.resize(len);
|
||||
break;
|
||||
}
|
||||
case eFileType_PNG:
|
||||
{
|
||||
stbi_write_png_to_func(&writeToByteVector, &encodedBytes, (int)thumbwidth, (int)thumbheight,
|
||||
3, thumbpixels, 0);
|
||||
break;
|
||||
}
|
||||
case eFileType_TGA:
|
||||
{
|
||||
stbi_write_tga_to_func(&writeToByteVector, &encodedBytes, (int)thumbwidth, (int)thumbheight,
|
||||
3, thumbpixels);
|
||||
break;
|
||||
}
|
||||
case eFileType_BMP:
|
||||
{
|
||||
stbi_write_bmp_to_func(&writeToByteVector, &encodedBytes, (int)thumbwidth, (int)thumbheight,
|
||||
3, thumbpixels);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
RDCERR("Unsupported file type %d in thumbnail fetch", type);
|
||||
free(thumbpixels);
|
||||
delete[] jpgbuf;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*buf = encodedBytes;
|
||||
|
||||
free(thumbpixels);
|
||||
}
|
||||
|
||||
delete[] jpgbuf;
|
||||
|
||||
|
||||
@@ -197,7 +197,13 @@ struct ThumbCommand : public Command
|
||||
virtual void AddOptions(cmdline::parser &parser)
|
||||
{
|
||||
parser.set_footer("<filename.rdc>");
|
||||
parser.add<string>("out", 'o', "The output filename to save the jpg to", false, "filename.jpg");
|
||||
parser.add<string>("out", 'o', "The output filename to save the file to", true, "filename.jpg");
|
||||
parser.add<string>("format", 'f',
|
||||
"The format of the output file. If empty, detected from filename", false, "",
|
||||
cmdline::oneof<string>("jpg", "png", "bmp", "tga"));
|
||||
parser.add<uint32_t>(
|
||||
"max-size", 's',
|
||||
"The maximum dimension of the thumbnail. Default is 0, which is unlimited.", false, 0);
|
||||
}
|
||||
virtual const char *Description() { return "Saves a capture's embedded thumbnail to disk."; }
|
||||
virtual bool IsInternalOnly() { return false; }
|
||||
@@ -214,33 +220,42 @@ struct ThumbCommand : public Command
|
||||
|
||||
string filename = parser.rest()[0];
|
||||
|
||||
string jpgname;
|
||||
string outfile = parser.get<string>("out");
|
||||
|
||||
if(parser.exist("out"))
|
||||
string format = parser.get<string>("format");
|
||||
|
||||
FileType type = eFileType_JPG;
|
||||
|
||||
if(format == "png")
|
||||
{
|
||||
jpgname = parser.get<string>("out");
|
||||
type = eFileType_PNG;
|
||||
}
|
||||
else if(format == "tga")
|
||||
{
|
||||
type = eFileType_TGA;
|
||||
}
|
||||
else if(format == "bmp")
|
||||
{
|
||||
type = eFileType_BMP;
|
||||
}
|
||||
else
|
||||
{
|
||||
jpgname = filename;
|
||||
const char *dot = strrchr(outfile.c_str(), '.');
|
||||
|
||||
if(jpgname[jpgname.length() - 4] == '.' && jpgname[jpgname.length() - 3] == 'r' &&
|
||||
jpgname[jpgname.length() - 2] == 'd' && jpgname[jpgname.length() - 1] == 'c')
|
||||
{
|
||||
jpgname.pop_back();
|
||||
jpgname.pop_back();
|
||||
jpgname.pop_back();
|
||||
|
||||
jpgname += "jpg";
|
||||
}
|
||||
if(dot != NULL && strstr(dot, "png"))
|
||||
type = eFileType_PNG;
|
||||
else if(dot != NULL && strstr(dot, "tga"))
|
||||
type = eFileType_TGA;
|
||||
else if(dot != NULL && strstr(dot, "bmp"))
|
||||
type = eFileType_BMP;
|
||||
else
|
||||
{
|
||||
jpgname += ".jpg";
|
||||
}
|
||||
std::cerr << "Couldn't guess format from '" << outfile << "', defaulting to jpg."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
uint32_t len = 0;
|
||||
bool32 ret = RENDERDOC_GetThumbnail(filename.c_str(), NULL, len);
|
||||
rdctype::array<byte> buf;
|
||||
bool32 ret =
|
||||
RENDERDOC_GetThumbnail(filename.c_str(), type, parser.get<uint32_t>("max-size"), &buf);
|
||||
|
||||
if(!ret)
|
||||
{
|
||||
@@ -248,24 +263,19 @@ struct ThumbCommand : public Command
|
||||
}
|
||||
else
|
||||
{
|
||||
byte *jpgbuf = new byte[len];
|
||||
RENDERDOC_GetThumbnail(filename.c_str(), jpgbuf, len);
|
||||
|
||||
FILE *f = fopen(jpgname.c_str(), "wb");
|
||||
FILE *f = fopen(outfile.c_str(), "wb");
|
||||
|
||||
if(!f)
|
||||
{
|
||||
std::cerr << "Couldn't open destination file '" << jpgname << "'" << std::endl;
|
||||
std::cerr << "Couldn't open destination file '" << outfile << "'" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
fwrite(jpgbuf, 1, len, f);
|
||||
fwrite(buf.elems, 1, buf.count, f);
|
||||
fclose(f);
|
||||
|
||||
std::cout << "Wrote thumbnail from '" << filename << "' to '" << jpgname << "'." << std::endl;
|
||||
std::cout << "Wrote thumbnail from '" << filename << "' to '" << outfile << "'." << std::endl;
|
||||
}
|
||||
|
||||
delete[] jpgbuf;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace renderdoc
|
||||
private static extern void RENDERDOC_SetConfigSetting(IntPtr name, IntPtr value);
|
||||
|
||||
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool RENDERDOC_GetThumbnail(IntPtr filename, byte[] outmem, ref UInt32 len);
|
||||
private static extern bool RENDERDOC_GetThumbnail(IntPtr filename, FileType type, UInt32 maxsize, IntPtr outmem);
|
||||
|
||||
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr RENDERDOC_MakeEnvironmentModificationList(int numElems);
|
||||
@@ -362,13 +362,15 @@ namespace renderdoc
|
||||
CustomMarshal.Free(value_mem);
|
||||
}
|
||||
|
||||
public static byte[] GetThumbnail(string filename)
|
||||
public static byte[] GetThumbnail(string filename, FileType type, UInt32 maxsize)
|
||||
{
|
||||
UInt32 len = 0;
|
||||
|
||||
IntPtr filename_mem = CustomMarshal.MakeUTF8String(filename);
|
||||
|
||||
bool success = RENDERDOC_GetThumbnail(filename_mem, null, ref len);
|
||||
IntPtr mem = CustomMarshal.Alloc(typeof(templated_array));
|
||||
|
||||
bool success = RENDERDOC_GetThumbnail(filename_mem, type, maxsize, mem);
|
||||
|
||||
if (!success || len == 0)
|
||||
{
|
||||
@@ -376,14 +378,9 @@ namespace renderdoc
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] ret = new byte[len];
|
||||
byte[] ret = (byte[])CustomMarshal.GetTemplatedArray(mem, typeof(byte), true);
|
||||
|
||||
success = RENDERDOC_GetThumbnail(filename_mem, ret, ref len);
|
||||
|
||||
CustomMarshal.Free(filename_mem);
|
||||
|
||||
if (!success || len == 0)
|
||||
return null;
|
||||
CustomMarshal.Free(mem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user