Unverified Commit 187b73f7 authored by Adrià Arrufat's avatar Adrià Arrufat Committed by GitHub
Browse files

Draw string on images (#2270)

* add function to draw string on images

* add documentation

* formatting

* add semicolon

* add test for draw_string on images
parent 74baff13
......@@ -7,6 +7,7 @@
#include "../algs.h"
#include "../pixel.h"
#include "../matrix.h"
#include "../gui_widgets.h"
#include <cmath>
namespace dlib
......@@ -224,6 +225,104 @@ namespace dlib
}
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename traits,
typename alloc,
typename image_type,
typename pixel_type
>
void draw_string (
image_type& c,
const dlib::point& p,
const std::basic_string<T,traits,alloc>& str,
const pixel_type& color,
const std::shared_ptr<font>& f_ptr = default_font::get_font(),
typename std::basic_string<T,traits,alloc>::size_type first = 0,
typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos)
)
{
using string = std::basic_string<T,traits,alloc>;
DLIB_ASSERT((last == string::npos) || (first <= last && last < str.size()),
"\tvoid dlib::draw_string()"
<< "\n\tlast == string::npos: " << ((last == string::npos)?"true":"false")
<< "\n\tfirst: " << (unsigned long)first
<< "\n\tlast: " << (unsigned long)last
<< "\n\tstr.size(): " << (unsigned long)str.size());
if (last == string::npos)
last = str.size()-1;
const rectangle rect(p, p);
const font& f = *f_ptr;
long y_offset = rect.top() + f.ascender() - 1;
long pos = rect.left()+f.left_overflow();
for (typename string::size_type i = first; i <= last; ++i)
{
// ignore the '\r' character
if (str[i] == '\r')
continue;
// A combining character should be applied to the previous character, and we
// therefore make one step back. If a combining comes right after a newline,
// then there must be some kind of error in the string, and we don't combine.
if(is_combining_char(str[i]) &&
pos > rect.left() + static_cast<long>(f.left_overflow()))
{
pos -= f[str[i]].width();
}
if (str[i] == '\n')
{
y_offset += f.height();
pos = rect.left()+f.left_overflow();
continue;
}
// only look at letters in the intersection area
if (c.nr() + static_cast<long>(f.height()) < y_offset)
{
// the string is now below our rectangle so we are done
break;
}
else if (0 > pos - static_cast<long>(f.left_overflow()) &&
pos + static_cast<long>(f[str[i]].width() + f.right_overflow()) < 0)
{
pos += f[str[i]].width();
continue;
}
else if (c.nc() + static_cast<long>(f.right_overflow()) < pos)
{
// keep looking because there might be a '\n' in the string that
// will wrap us around and put us back into our rectangle.
continue;
}
// at this point in the loop we know that f[str[i]] overlaps
// horizontally with the intersection rectangle area.
const letter& l = f[str[i]];
for (unsigned short i = 0; i < l.num_of_points(); ++i)
{
const long x = l[i].x + pos;
const long y = l[i].y + y_offset;
// draw each pixel of the letter if it is inside the intersection
// rectangle
if (x >= 0 && x < c.nc() && y >= 0 && y < c.nr())
{
assign_pixel(c(y, x), color);
}
}
pos += l.width();
}
}
// ----------------------------------------------------------------------------------------
template <
......
......@@ -79,6 +79,36 @@ namespace dlib
- The drawn rectangle will have edges that are thickness pixels wide.
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
typename traits,
typename alloc,
typename image_type,
typename pixel_type
>
void draw_string (
image_type& img,
const dlib::point& p,
const std::basic_string<T,traits,alloc>& str,
const pixel_type& val,
const std::shared_ptr<font>& f = default_font::get_font(),
typename std::basic_string<T,traits,alloc>::size_type first = 0,
typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos)
);
/*!
requires
- image_type == an image object that implements the interface defined in
dlib/image_processing/generic_image.h
- pixel_traits<pixel_type> is defined
ensures
- Draws the given string from first to last character onto the image img
starting from point p.
- The string is drawn with the color given by val and font f;
!*/
// ----------------------------------------------------------------------------------------
template <
......
......@@ -10,6 +10,8 @@
#include <dlib/image_io.h>
#include <dlib/matrix.h>
#include <dlib/rand.h>
#include <dlib/compress_stream.h>
#include <dlib/base64.h>
#include "tester.h"
......@@ -2254,7 +2256,32 @@ namespace
}
}
}
void test_draw_string()
{
print_spinner();
matrix<rgb_pixel> image{48, 48};
assign_all_pixels(image, rgb_pixel{0, 0, 0});
draw_string(image, point{10, 15}, string{"cat"}, rgb_pixel{255, 255, 255});
matrix<rgb_pixel> result;
const std::string data{"gQgLudERwR0JqP9kUiitFNDYSO9rdZzdmeDmricAlM5f5RBqzTlaW6Lp704mTXJq/WXHTQ84wWnGAA=="};
ostringstream sout;
istringstream sin;
base64 base64_coder;
compress_stream::kernel_1ea compressor;
sin.str(data);
base64_coder.decode(sin, sout);
sin.clear();
sin.str(sout.str());
sout.clear();
sout.str("");
compressor.decompress(sin, sout);
sin.clear();
sin.str(sout.str());
deserialize(result, sin);
DLIB_TEST(image == result);
}
// ----------------------------------------------------------------------------------------
......@@ -2359,6 +2386,7 @@ namespace
test_null_rotate_image_with_interpolation();
test_null_rotate_image_with_interpolation_quadratic();
test_interpolate_bilinear();
test_draw_string();
}
} a;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment