Add processing to different formats and max size while fetching thumb

This commit is contained in:
baldurk
2016-11-01 16:56:49 +01:00
parent 57d8cfa89a
commit 5286f950ff
5 changed files with 156 additions and 61 deletions
+3 -2
View File
@@ -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);
+6 -9
View File
@@ -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);
+102 -12
View File
@@ -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;
+38 -28
View File
@@ -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;
+7 -10
View File
@@ -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;
}