mirror of
https://github.com/QIDITECH/QIDISlicer.git
synced 2026-02-02 08:58:43 +03:00
QIDISlicer1.0.0
This commit is contained in:
436
src/libslic3r/GCode/Thumbnails.cpp
Normal file
436
src/libslic3r/GCode/Thumbnails.cpp
Normal file
@@ -0,0 +1,436 @@
|
||||
#include "Thumbnails.hpp"
|
||||
#include "../miniz_extension.hpp"
|
||||
|
||||
#include <qoi/qoi.h>
|
||||
#include <jpeglib.h>
|
||||
#include <jerror.h>
|
||||
#include<stdio.h>
|
||||
#include<string.h>
|
||||
// #include "colpic3.h"
|
||||
namespace Slic3r::GCodeThumbnails {
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
struct CompressedPNG : CompressedImageBuffer
|
||||
{
|
||||
~CompressedPNG() override { if (data) mz_free(data); }
|
||||
std::string_view tag() const override { return "thumbnail"sv; }
|
||||
};
|
||||
|
||||
struct CompressedJPG : CompressedImageBuffer
|
||||
{
|
||||
~CompressedJPG() override { free(data); }
|
||||
std::string_view tag() const override { return "thumbnail_JPG"sv; }
|
||||
};
|
||||
|
||||
struct CompressedQOI : CompressedImageBuffer
|
||||
{
|
||||
~CompressedQOI() override { free(data); }
|
||||
std::string_view tag() const override { return "thumbnail_QOI"sv; }
|
||||
};
|
||||
|
||||
|
||||
std::unique_ptr<CompressedImageBuffer> compress_thumbnail_png(
|
||||
const ThumbnailData& data){
|
||||
auto out = std::make_unique<CompressedPNG>();
|
||||
out->data = tdefl_write_image_to_png_file_in_memory_ex((const
|
||||
void*)data.pixels.data(), data.width, data.height, 4, &out->size,
|
||||
MZ_DEFAULT_LEVEL, 1);
|
||||
return out;
|
||||
}
|
||||
// B3
|
||||
std::string compress_qidi_thumbnail_png(const ThumbnailData &data)
|
||||
{
|
||||
auto out = std::make_unique<CompressedPNG>();
|
||||
//BOOST_LOG_TRIVIAL(error) << data.width;
|
||||
int width = int(data.width);
|
||||
int height = int(data.height);
|
||||
|
||||
if (data.width * data.height > 500 * 500) {
|
||||
width = 500;
|
||||
height = 500;
|
||||
}
|
||||
U16 color16[500*500];
|
||||
//U16 *color16 = new U16[data.width * data.height];
|
||||
//for (int i = 0; i < 200*200; i++) color16[i] = 522240;
|
||||
unsigned char outputdata[500 * 500 * 10];
|
||||
//unsigned char *outputdata = new unsigned char[data.width * data.height * 10];
|
||||
|
||||
std::vector<uint8_t> rgba_pixels(data.pixels.size() * 4);
|
||||
size_t row_size = width * 4;
|
||||
for (size_t y = 0; y <height; ++y)
|
||||
memcpy(rgba_pixels.data() + (height - y - 1) * row_size,
|
||||
data.pixels.data() + y * row_size, row_size);
|
||||
const unsigned char *pixels;
|
||||
pixels = (const unsigned char *) rgba_pixels.data();
|
||||
int rrrr=0, gggg=0, bbbb=0, aaaa=0,rgb=0;
|
||||
|
||||
int time = width * height-1; // 200*200-1;
|
||||
|
||||
for (unsigned int r = 0; r < height; ++r) {
|
||||
unsigned int rr = (height - 1 - r) * width;
|
||||
for (unsigned int c = 0; c < width; ++c) {
|
||||
rrrr = int(pixels[4 * (rr + c) + 0]) >> 3;
|
||||
gggg = int(pixels[4 * (rr + c) + 1]) >> 2;
|
||||
bbbb = int(pixels[4 * (rr + c) + 2]) >> 3;
|
||||
aaaa = int(pixels[4 * (rr + c) + 3]);
|
||||
if (aaaa == 0) {
|
||||
rrrr = 239 >> 3;
|
||||
gggg = 243 >> 2;
|
||||
bbbb = 247 >> 3;
|
||||
}
|
||||
rgb = (rrrr << 11) | (gggg << 5) | bbbb;
|
||||
color16[time--] = rgb;
|
||||
}
|
||||
}
|
||||
|
||||
int res = ColPic_EncodeStr(color16, width, height, outputdata,
|
||||
height * width * 10,
|
||||
1024);
|
||||
std::string temp;
|
||||
|
||||
//for (unsigned char i : outputdata) { temp += i; }
|
||||
for (unsigned int i = 0; i < sizeof(outputdata); ++i) {
|
||||
temp +=outputdata[i];
|
||||
// unsigned char strr = outputdata[i];
|
||||
// temp += strr;
|
||||
}
|
||||
//out->data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &out->size, MZ_DEFAULT_LEVEL, 1);
|
||||
return temp;
|
||||
}
|
||||
|
||||
std::unique_ptr<CompressedImageBuffer> compress_thumbnail_jpg(const ThumbnailData& data)
|
||||
{
|
||||
// Take vector of RGBA pixels and flip the image vertically
|
||||
std::vector<unsigned char> rgba_pixels(data.pixels.size());
|
||||
const unsigned int row_size = data.width * 4;
|
||||
for (unsigned int y = 0; y < data.height; ++y) {
|
||||
::memcpy(rgba_pixels.data() + (data.height - y - 1) * row_size, data.pixels.data() + y * row_size, row_size);
|
||||
}
|
||||
|
||||
// Store pointers to scanlines start for later use
|
||||
std::vector<unsigned char*> rows_ptrs;
|
||||
rows_ptrs.reserve(data.height);
|
||||
for (unsigned int y = 0; y < data.height; ++y) {
|
||||
rows_ptrs.emplace_back(&rgba_pixels[y * row_size]);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> compressed_data(data.pixels.size());
|
||||
unsigned char* compressed_data_ptr = compressed_data.data();
|
||||
unsigned long compressed_data_size = data.pixels.size();
|
||||
|
||||
jpeg_error_mgr err;
|
||||
jpeg_compress_struct info;
|
||||
info.err = jpeg_std_error(&err);
|
||||
jpeg_create_compress(&info);
|
||||
jpeg_mem_dest(&info, &compressed_data_ptr, &compressed_data_size);
|
||||
|
||||
info.image_width = data.width;
|
||||
info.image_height = data.height;
|
||||
info.input_components = 4;
|
||||
info.in_color_space = JCS_EXT_RGBA;
|
||||
|
||||
jpeg_set_defaults(&info);
|
||||
jpeg_set_quality(&info, 85, TRUE);
|
||||
jpeg_start_compress(&info, TRUE);
|
||||
|
||||
jpeg_write_scanlines(&info, rows_ptrs.data(), data.height);
|
||||
jpeg_finish_compress(&info);
|
||||
jpeg_destroy_compress(&info);
|
||||
|
||||
// FIXME -> Add error checking
|
||||
|
||||
auto out = std::make_unique<CompressedJPG>();
|
||||
out->data = malloc(compressed_data_size);
|
||||
out->size = size_t(compressed_data_size);
|
||||
::memcpy(out->data, (const void*)compressed_data.data(), out->size);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::unique_ptr<CompressedImageBuffer> compress_thumbnail_qoi(const ThumbnailData &data)
|
||||
{
|
||||
qoi_desc desc;
|
||||
desc.width = data.width;
|
||||
desc.height = data.height;
|
||||
desc.channels = 4;
|
||||
desc.colorspace = QOI_SRGB;
|
||||
|
||||
// Take vector of RGBA pixels and flip the image vertically
|
||||
std::vector<uint8_t> rgba_pixels(data.pixels.size() * 4);
|
||||
size_t row_size = data.width * 4;
|
||||
for (size_t y = 0; y < data.height; ++ y)
|
||||
memcpy(rgba_pixels.data() + (data.height - y - 1) * row_size, data.pixels.data() + y * row_size, row_size);
|
||||
|
||||
auto out = std::make_unique<CompressedQOI>();
|
||||
int size;
|
||||
out->data = qoi_encode((const void*)rgba_pixels.data(), &desc, &size);
|
||||
out->size = size;
|
||||
return out;
|
||||
}
|
||||
|
||||
//B3
|
||||
std::string compress_qidi_thumbnail(const ThumbnailData& data,
|
||||
GCodeThumbnailsFormat format)
|
||||
{
|
||||
return compress_qidi_thumbnail_png(data);
|
||||
}
|
||||
|
||||
//B3
|
||||
std::unique_ptr<CompressedImageBuffer> compress_thumbnail(const ThumbnailData &data, GCodeThumbnailsFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case GCodeThumbnailsFormat::PNG:
|
||||
default:
|
||||
return compress_thumbnail_png(data);
|
||||
case GCodeThumbnailsFormat::JPG:
|
||||
return compress_thumbnail_jpg(data);
|
||||
case GCodeThumbnailsFormat::QOI:
|
||||
return compress_thumbnail_qoi(data);
|
||||
}
|
||||
}
|
||||
static void colmemmove(U8 *dec, U8 *src, int lenth)
|
||||
{
|
||||
if (src < dec) {
|
||||
dec += lenth - 1;
|
||||
src += lenth - 1;
|
||||
while (lenth > 0) {
|
||||
*(dec--) = *(src--);
|
||||
lenth--;
|
||||
}
|
||||
} else {
|
||||
while (lenth > 0) {
|
||||
*(dec++) = *(src++);
|
||||
lenth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void colmemcpy(U8 *dec, U8 *src, int lenth)
|
||||
{
|
||||
while (lenth > 0) {
|
||||
*(dec++) = *(src++);
|
||||
lenth--;
|
||||
}
|
||||
}
|
||||
static void colmemset(U8 *dec, U8 val, int lenth)
|
||||
{
|
||||
while (lenth > 0) {
|
||||
*(dec++) = val;
|
||||
lenth--;
|
||||
}
|
||||
}
|
||||
static void ADList0(U16 val, U16HEAD *listu16, int *listqty, int maxqty)
|
||||
{
|
||||
U8 A0;
|
||||
U8 A1;
|
||||
U8 A2;
|
||||
int qty = *listqty;
|
||||
if (qty >= maxqty) return;
|
||||
for (int i = 0; i < qty; i++) {
|
||||
if (listu16[i].colo16 == val) {
|
||||
listu16[i].qty++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
A0 = (U8) (val >> 11);
|
||||
A1 = (U8) ((val << 5) >> 10);
|
||||
A2 = (U8) ((val << 11) >> 11);
|
||||
U16HEAD *a = &listu16[qty];
|
||||
a->colo16 = val;
|
||||
a->A0 = A0;
|
||||
a->A1 = A1;
|
||||
a->A2 = A2;
|
||||
a->qty = 1;
|
||||
*listqty = qty + 1;
|
||||
}
|
||||
static int Byte8bitEncode(U16 *fromcolor16,
|
||||
U16 *listu16,
|
||||
int listqty,
|
||||
int dotsqty,
|
||||
U8 * outputdata,
|
||||
int decMaxBytesize)
|
||||
{
|
||||
U8 tid, sid;
|
||||
int dots = 0;
|
||||
int srcindex = 0;
|
||||
int decindex = 0;
|
||||
int lastid = 0;
|
||||
int temp = 0;
|
||||
while (dotsqty > 0) {
|
||||
dots = 1;
|
||||
for (int i = 0; i < (dotsqty - 1); i++) {
|
||||
if (fromcolor16[srcindex + i] != fromcolor16[srcindex + i + 1])
|
||||
break;
|
||||
dots++;
|
||||
if (dots == 255) break;
|
||||
}
|
||||
temp = 0;
|
||||
for (int i = 0; i < listqty; i++) {
|
||||
if (listu16[i] == fromcolor16[srcindex]) {
|
||||
temp = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
tid = (U8) (temp % 32);
|
||||
sid = (U8) (temp / 32);
|
||||
if (lastid != sid) {
|
||||
if (decindex >= decMaxBytesize) goto IL_END;
|
||||
outputdata[decindex] = 7;
|
||||
outputdata[decindex] <<= 5;
|
||||
outputdata[decindex] += sid;
|
||||
decindex++;
|
||||
lastid = sid;
|
||||
}
|
||||
if (dots <= 6) {
|
||||
if (decindex >= decMaxBytesize) goto IL_END;
|
||||
outputdata[decindex] = (U8) dots;
|
||||
outputdata[decindex] <<= 5;
|
||||
outputdata[decindex] += tid;
|
||||
decindex++;
|
||||
} else {
|
||||
if (decindex >= decMaxBytesize) goto IL_END;
|
||||
outputdata[decindex] = 0;
|
||||
outputdata[decindex] += tid;
|
||||
decindex++;
|
||||
if (decindex >= decMaxBytesize) goto IL_END;
|
||||
outputdata[decindex] = (U8) dots;
|
||||
decindex++;
|
||||
}
|
||||
srcindex += dots;
|
||||
dotsqty -= dots;
|
||||
}
|
||||
IL_END:
|
||||
return decindex;
|
||||
}
|
||||
static int ColPicEncode(U16 *fromcolor16,
|
||||
int picw,
|
||||
int pich,
|
||||
U8 * outputdata,
|
||||
int outputmaxtsize,
|
||||
int colorsmax)
|
||||
{
|
||||
U16HEAD l0;
|
||||
int cha0, cha1, cha2, fid, minval;
|
||||
ColPicHead3 *Head0 = null;
|
||||
U16HEAD Listu16[1024];
|
||||
int ListQty = 0;
|
||||
int enqty = 0;
|
||||
int dotsqty = picw * pich;
|
||||
if (colorsmax > 1024) colorsmax = 1024;
|
||||
for (int i = 0; i < dotsqty; i++) {
|
||||
int ch = (int) fromcolor16[i];
|
||||
ADList0(ch, Listu16, &ListQty, 1024);
|
||||
}
|
||||
|
||||
|
||||
for (int index = 1; index < ListQty; index++) {
|
||||
l0 = Listu16[index];
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (l0.qty >= Listu16[i].qty) {
|
||||
colmemmove((U8 *) &Listu16[i + 1], (U8 *) &Listu16[i],
|
||||
(index - i) * sizeof(U16HEAD));
|
||||
colmemcpy((U8 *) &Listu16[i], (U8 *) &l0, sizeof(U16HEAD));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ListQty > colorsmax) {
|
||||
l0 = Listu16[ListQty - 1];
|
||||
minval = 255;
|
||||
fid = -1;
|
||||
for (int i = 0; i < colorsmax; i++) {
|
||||
cha0 = Listu16[i].A0 - l0.A0;
|
||||
if (cha0 < 0) cha0 = 0 - cha0;
|
||||
cha1 = Listu16[i].A1 - l0.A1;
|
||||
if (cha1 < 0) cha1 = 0 - cha1;
|
||||
cha2 = Listu16[i].A2 - l0.A2;
|
||||
if (cha2 < 0) cha2 = 0 - cha2;
|
||||
int chall = cha0 + cha1 + cha2;
|
||||
if (chall < minval) {
|
||||
minval = chall;
|
||||
fid = i;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < dotsqty; i++) {
|
||||
if (fromcolor16[i] == l0.colo16)
|
||||
fromcolor16[i] = Listu16[fid].colo16;
|
||||
}
|
||||
ListQty = ListQty - 1;
|
||||
}
|
||||
Head0 = ((ColPicHead3 *) outputdata);
|
||||
colmemset(outputdata, 0, sizeof(ColPicHead3));
|
||||
Head0->encodever = 3;
|
||||
Head0->oncelistqty = 0;
|
||||
Head0->mark = 0x05DDC33C;
|
||||
Head0->ListDataSize = ListQty * 2;
|
||||
for (int i = 0; i < ListQty; i++) {
|
||||
U16 *l0 = (U16 *) &outputdata[sizeof(ColPicHead3)];
|
||||
l0[i] = Listu16[i].colo16;
|
||||
}
|
||||
enqty =
|
||||
Byte8bitEncode(fromcolor16, (U16 *) &outputdata[sizeof(ColPicHead3)],
|
||||
Head0->ListDataSize >> 1, dotsqty,
|
||||
&outputdata[sizeof(ColPicHead3) + Head0->ListDataSize],
|
||||
outputmaxtsize - sizeof(ColPicHead3) -
|
||||
Head0->ListDataSize);
|
||||
Head0->ColorDataSize = enqty;
|
||||
Head0->PicW = picw;
|
||||
Head0->PicH = pich;
|
||||
return sizeof(ColPicHead3) + Head0->ListDataSize + Head0->ColorDataSize;
|
||||
}
|
||||
int ColPic_EncodeStr(U16 *fromcolor16,
|
||||
int picw,
|
||||
int pich,
|
||||
U8 * outputdata,
|
||||
int outputmaxtsize,
|
||||
int colorsmax)
|
||||
{
|
||||
int qty = 0;
|
||||
int temp = 0;
|
||||
int strindex = 0;
|
||||
int hexindex = 0;
|
||||
U8 TempBytes[4];
|
||||
qty = ColPicEncode(fromcolor16, picw, pich, outputdata, outputmaxtsize,
|
||||
colorsmax);
|
||||
if (qty == 0) return 0;
|
||||
temp = 3 - (qty % 3);
|
||||
while (temp > 0) {
|
||||
outputdata[qty] = 0;
|
||||
qty++;
|
||||
temp--;
|
||||
}
|
||||
if ((qty * 4 / 3) >= outputmaxtsize) return 0;
|
||||
hexindex = qty;
|
||||
strindex = (qty * 4 / 3);
|
||||
while (hexindex > 0) {
|
||||
hexindex -= 3;
|
||||
strindex -= 4;
|
||||
|
||||
TempBytes[0] = (U8) (outputdata[hexindex] >> 2);
|
||||
TempBytes[1] = (U8) (outputdata[hexindex] & 3);
|
||||
TempBytes[1] <<= 4;
|
||||
TempBytes[1] += ((U8) (outputdata[hexindex + 1] >> 4));
|
||||
TempBytes[2] = (U8) (outputdata[hexindex + 1] & 15);
|
||||
TempBytes[2] <<= 2;
|
||||
TempBytes[2] += ((U8) (outputdata[hexindex + 2] >> 6));
|
||||
TempBytes[3] = (U8) (outputdata[hexindex + 2] & 63);
|
||||
|
||||
TempBytes[0] += 48;
|
||||
if (TempBytes[0] == (U8) '\\') TempBytes[0] = 126;
|
||||
TempBytes[0 + 1] += 48;
|
||||
if (TempBytes[0 + 1] == (U8) '\\') TempBytes[0 + 1] = 126;
|
||||
TempBytes[0 + 2] += 48;
|
||||
if (TempBytes[0 + 2] == (U8) '\\') TempBytes[0 + 2] = 126;
|
||||
TempBytes[0 + 3] += 48;
|
||||
if (TempBytes[0 + 3] == (U8) '\\') TempBytes[0 + 3] = 126;
|
||||
|
||||
outputdata[strindex] = TempBytes[0];
|
||||
outputdata[strindex + 1] = TempBytes[1];
|
||||
outputdata[strindex + 2] = TempBytes[2];
|
||||
outputdata[strindex + 3] = TempBytes[3];
|
||||
}
|
||||
qty = qty * 4 / 3;
|
||||
outputdata[qty] = 0;
|
||||
return qty;
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GCodeThumbnails
|
||||
Reference in New Issue
Block a user