added truetype font support into OpenCV, based on STB_truetype

pull/18760/head
Vadim Pisarevsky 4 years ago
parent 1088d95c50
commit d42665d9e2
  1. 7
      CMakeLists.txt
  2. 25
      cmake/OpenCVUtils.cmake
  3. 3
      cmake/templates/cvconfig.h.in
  4. 8
      modules/core/include/opencv2/core/cvdef.h
  5. 8
      modules/core/misc/objc/common/Range.h
  6. 96
      modules/core/misc/objc/common/Range.mm
  7. 4
      modules/core/misc/objc/gen_dict.json
  8. 41
      modules/imgproc/CMakeLists.txt
  9. BIN
      modules/imgproc/fonts/Rubik-Italic.ttf.gz
  10. BIN
      modules/imgproc/fonts/Rubik.ttf.gz
  11. 93
      modules/imgproc/fonts/Rubik_OFL.txt
  12. 107
      modules/imgproc/include/opencv2/imgproc.hpp
  13. 17
      modules/imgproc/misc/java/test/ImgprocTest.java
  14. 38
      modules/imgproc/misc/objc/common/FontFace.h
  15. 43
      modules/imgproc/misc/objc/common/FontFace.mm
  16. 10
      modules/imgproc/misc/objc/gen_dict.json
  17. 15
      modules/imgproc/misc/objc/test/ImgprocTest.swift
  18. 327
      modules/imgproc/src/drawing.cpp
  19. 1547
      modules/imgproc/src/drawing_text.cpp
  20. 3359
      modules/imgproc/src/hershey_fonts.cpp
  21. 4864
      modules/imgproc/src/stb_truetype.cpp
  22. 692
      modules/imgproc/src/stb_truetype.hpp
  23. 181
      modules/imgproc/test/test_drawing.cpp
  24. 13
      modules/videoio/include/opencv2/videoio/legacy/constants_c.h
  25. 6
      platforms/ios/build_framework.py
  26. 2
      platforms/ios/run_tests.py

@ -508,6 +508,9 @@ OCV_OPTION(OPENCV_ENABLE_MEMALIGN "Enable posix_memalign or memalign usage"
OCV_OPTION(ENABLE_PYLINT "Add target with Pylint checks" (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
OCV_OPTION(ENABLE_FLAKE8 "Add target with Python flake8 checker" (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
OCV_OPTION(WITH_UNIFONT "Build 'uni' font (WQY MicroHei) into OpenCV" (NOT BUILD_opencv_js)
VERIFY HAVE_UNIFONT)
if(ENABLE_IMPL_COLLECTION)
add_definitions(-DCV_COLLECT_IMPL_DATA)
endif()
@ -1238,6 +1241,10 @@ if(WITH_VTK OR HAVE_VTK)
status(" VTK support:" HAVE_VTK THEN "YES (ver ${VTK_VERSION})" ELSE NO)
endif()
if(WITH_UNIFONT OR HAVE_UNIFONT)
status(" Built-in Unicode font:" HAVE_UNIFONT THEN "YES" ELSE "NO")
endif()
# ========================== MEDIA IO ==========================
status("")
status(" Media I/O: ")

@ -1881,3 +1881,28 @@ function(ocv_update_file filepath content)
file(WRITE "${filepath}" "${content}")
endif()
endfunction()
# adopted from https://gist.github.com/amir-saniyan/de99cee82fa9d8d615bb69f3f53b6004
function(ocv_blob2hdr blob_filename hdr_filename cpp_variable)
if(EXISTS "${hdr_filename}")
if("${hdr_filename}" IS_NEWER_THAN "${blob_filename}")
return()
endif()
endif()
file(READ "${blob_filename}" hex_content HEX)
# repeat [0-9a-f] 32 times
set(pattern "[0-9a-f][0-9a-f][0-9a-f][0-9a-f]")
set(pattern "${pattern}${pattern}")
set(pattern "${pattern}${pattern}")
set(pattern "${pattern}${pattern}")
string(REGEX REPLACE "(${pattern})" "\\1\n" content "${hex_content}")
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " content "${content}")
string(REGEX REPLACE ", $" "" content "${content}")
set(array_definition "static const unsigned char ${cpp_variable}[] =\n{\n${content}\n};")
set(source "// Auto generated file.\n${array_definition}\n")
file(WRITE "${hdr_filename}" "${source}")
endfunction()

@ -164,4 +164,7 @@
/* Library QR-code decoding */
#cmakedefine HAVE_QUIRC
/* The font "uni" (WQY MicroHei) is available */
#cmakedefine HAVE_UNIFONT
#endif // OPENCV_CVCONFIG_H_INCLUDED

@ -915,6 +915,14 @@ protected:
}
#endif
/** @brief Constructs the 'fourcc' code, used in video codecs and many other places.
Simply call it with 4 chars like `CV_FOURCC('I', 'Y', 'U', 'V')`
*/
CV_INLINE int CV_FOURCC(char c1, char c2, char c3, char c4)
{
return (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24);
}
//! @}
#ifndef __cplusplus

@ -21,6 +21,10 @@ NS_ASSUME_NONNULL_BEGIN
*/
CV_EXPORTS @interface Range : NSObject
#ifdef __cplusplus
@property(readonly) cv::Range& nativeRef;
#endif
#pragma mark - Properties
@property int start;
@ -90,6 +94,10 @@ CV_EXPORTS @interface Range : NSObject
*/
- (NSString*)description;
#ifdef __cplusplus
+ (instancetype)fromNative:(cv::Range&)range;
#endif
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,96 @@
//
// Range.m
//
// Created by Giles Payne on 2019/10/08.
//
#import "Range.h"
@implementation Range {
cv::Range native;
}
- (cv::Range&)nativeRef {
return native;
}
- (instancetype)init {
return [self initWithStart:0 end: 0];
}
- (instancetype)initWithStart:(int)start end:(int)end {
self = [super init];
if (self != nil) {
self.start = start;
self.end = end;
}
return self;
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [self init];
if (self != nil) {
[self set:vals];
}
return self;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.start = (vals != nil && vals.count > 0) ? vals[0].intValue : 0;
self.end = (vals != nil && vals.count > 1 ) ? vals[1].intValue : 0;
}
- (int)size {
return [self empty] ? 0 : self.end - self.start;
}
- (BOOL)empty {
return self.end <= self.start;
}
+ (Range*)all {
return [[Range alloc] initWithStart:INT_MIN end:INT_MAX];
}
- (Range*)intersection:(Range*)r1 {
Range* out = [[Range alloc] initWithStart:MAX(r1.start, self.start) end:MIN(r1.end, self.end)];
out.end = MAX(out.end, out.start);
return out;
}
- (Range*)shift:(int)delta {
return [[Range alloc] initWithStart:self.start + delta end:self.end + delta];
}
- (Range*)clone {
return [[Range alloc] initWithStart:self.start end:self.end];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Range class]]) {
return NO;
} else {
Range* it = (Range*)other;
return self.start == it.start && self.end == it.end;
}
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
result = prime * result + self.start;
result = prime * result + self.end;
return result;
}
+ (instancetype)fromNative:(cv::Range&)range {
return [[Range alloc] initWithStart:range.start end:range.end];
}
- (NSString *)description {
return [NSString stringWithFormat:@"Range {%d, %d}", self.start, self.end];
}
@end

@ -147,7 +147,9 @@
"from_cpp": "[Point3i fromNative:%(n)s]"
},
"Range": {
"objc_type": "Range*"
"objc_type": "Range*",
"to_cpp": "%(n)s.nativeRef",
"from_cpp": "[Point3i fromNative:%(n)s]"
},
"Rect": {
"objc_type": "Rect2i*",

@ -12,8 +12,49 @@ ocv_add_dispatched_file(smooth SSE2 SSE4_1 AVX2)
ocv_add_dispatched_file(sumpixels SSE2 AVX2 AVX512_SKX)
ocv_define_module(imgproc opencv_core WRAP java objc python js)
ocv_module_include_directories(opencv_imgproc ${ZLIB_INCLUDE_DIRS})
ocv_check_environment_variables(OPENCV_IPP_GAUSSIAN_BLUR)
option(OPENCV_IPP_GAUSSIAN_BLUR "Enable IPP optimizations for GaussianBlur (+8Mb in binary size)" OFF)
if(OPENCV_IPP_GAUSSIAN_BLUR)
ocv_append_source_file_compile_definitions(${CMAKE_CURRENT_SOURCE_DIR}/src/smooth.dispatch.cpp "ENABLE_IPP_GAUSSIAN_BLUR=1")
endif()
set(UNIFONT_MD5 "fb79cf5b4f4c89414f1233f14c2eb273")
set(UNIFONT_NAME "WenQuanYiMicroHei.ttf.gz")
set(UNIFONT_COMMIT "cc7d85179d69a704bee209aa37ce8a657f2f8b34")
set(UNIFONT_URL "https://raw.githubusercontent.com/vpisarev/opencv_3rdparty/${UNIFONT_COMMIT}/")
unset(HAVE_UNIFONT)
unset(HAVE_UNIFONT CACHE)
if (WITH_UNIFONT)
ocv_download(FILENAME ${UNIFONT_NAME}
HASH ${UNIFONT_MD5}
URL
"${OPENCV_UNIFONT_URL}"
"${UNIFONT_URL}"
DESTINATION_DIR "${CMAKE_CURRENT_BINARY_DIR}"
ID UNIFONT
STATUS res
RELATIVE_URL)
if (res)
message(STATUS "Unicode font has been downloaded successfully.")
set(HAVE_UNIFONT ON CACHE INTERNAL "")
else()
message(STATUS "Unicode font download failed. Turning it off.")
set(HAVE_UNIFONT OFF CACHE INTERNAL "")
endif()
else()
set(HAVE_UNIFONT OFF CACHE INTERNAL "")
endif()
ocv_blob2hdr("${CMAKE_CURRENT_SOURCE_DIR}/fonts/Rubik.ttf.gz" "${CMAKE_CURRENT_BINARY_DIR}/builtin_font_sans.h" OcvBuiltinFontSans)
ocv_blob2hdr("${CMAKE_CURRENT_SOURCE_DIR}/fonts/Rubik-Italic.ttf.gz" "${CMAKE_CURRENT_BINARY_DIR}/builtin_font_italic.h" OcvBuiltinFontItalic)
if (HAVE_UNIFONT)
ocv_blob2hdr("${CMAKE_CURRENT_BINARY_DIR}/${UNIFONT_NAME}" "${CMAKE_CURRENT_BINARY_DIR}/builtin_font_uni.h" OcvBuiltinFontUni)
endif()
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
ocv_target_link_libraries(${the_module} LINK_PRIVATE ${ZLIB_LIBRARIES})
ocv_install_3rdparty_licenses(fonts fonts/Rubik_OFL.txt)

@ -0,0 +1,93 @@
Copyright 2015 The Rubik Project Authors (https://github.com/googlefonts/rubik),
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

@ -4631,6 +4631,113 @@ CV_EXPORTS_W double getFontScaleFromHeight(const int fontFace,
const int pixelHeight,
const int thickness = 1);
/** @brief Wrapper on top of a truetype/opentype/etc font, i.e. Freetype's FT_Face.
The class is used to store the loaded fonts;
the font can then be passed to the functions
putText and getTextSize.
*/
class CV_EXPORTS_W_SIMPLE FontFace
{
public:
/** @brief loads default font */
CV_WRAP FontFace();
/** @brief
loads font at the specified path or with specified name.
Empty fontPathOrName means the default embedded font.
*/
CV_WRAP FontFace(const String& fontPathOrName);
~FontFace();
/** @brief loads new font face */
CV_WRAP bool set(const String& fontPathOrName);
CV_WRAP String getName() const;
/** @brief sets the current variable font instance.
@param params The list of pairs key1, value1, key2, value2, ..., e.g.
`myfont.setInstance({CV_FOURCC('w','g','h','t'), 400<<16, CV_FOURCC('s','l','n','t'), -(15<<16)});`
Note that the parameter values are specified in 16.16 fixed-point format, that is, integer values
need to be shifted by 16 (or multiplied by 65536).
*/
CV_WRAP bool setInstance(const std::vector<int>& params);
CV_WRAP bool getInstance(CV_OUT std::vector<int>& params) const;
struct Impl;
Impl* operator -> ();
static bool getBuiltinFontData(const String& fontName, const uchar*& data, size_t& datasize);
protected:
Ptr<Impl> impl;
};
/** @brief Defines various put text flags */
enum PutTextFlags
{
PUT_TEXT_ALIGN_LEFT=0, // put the text to the right from the origin
PUT_TEXT_ALIGN_CENTER=1,// center the text at the origin; not implemented yet
PUT_TEXT_ALIGN_RIGHT=2, // put the text to the left of the origin
PUT_TEXT_ALIGN_MASK=3, // alignment mask
PUT_TEXT_ORIGIN_TL=0,
PUT_TEXT_ORIGIN_BL=32, // treat the target image as having bottom-left origin
PUT_TEXT_WRAP=128 // wrap text to the next line if it does not fit
};
/** @brief Draws a text string using specified font.
The function cv::putText renders the specified text string in the image. Symbols that cannot be rendered
using the specified font are replaced by question marks. See #getTextSize for a text rendering code
example. The function returns the coordinates in pixels from where the text can be continued.
@param img Image.
@param text Text string to be drawn.
@param org Bottom-left corner of the first character of the printed text
(see PUT_TEXT_ALIGN_... though)
@param color Text color.
@param fface The font to use for the text
@param size Font size in pixels (by default) or pts
@param weight Font weight, 100..1000,
where 100 is "thin" font, 400 is "regular",
600 is "semibold", 800 is "bold" and beyond that is "black".
The parameter is ignored if the font is not a variable font or if it does not provide variation along 'wght' axis.
If the weight is 0, then the weight, currently set via setInstance(), is used.
@param flags Various flags, see PUT_TEXT_...
@param wrap The optional text wrapping range:
In the case of left-to-right (LTR) text if the printed character would cross wrap.end boundary,
the "cursor" is set to wrap.start.
In the case of right-to-left (RTL) text it's vice versa.
If the parameters is not set,
[org.x, img.cols] is used for LTR text and
[0, org.x] is for RTL one.
*/
CV_EXPORTS_W Point putText( InputOutputArray img, const String& text, Point org,
Scalar color, FontFace& fface, int size, int weight=0,
PutTextFlags flags=PUT_TEXT_ALIGN_LEFT, Range wrap=Range() );
/** @brief Calculates the bounding rect for the text
The function cv::getTextSize calculates and returns the size of a box that contains the specified text.
That is, the following code renders some text, the tight box surrounding it, and the baseline: :
@param imgsize Size of the target image, can be empty
@param text Text string to be drawn.
@param org Bottom-left corner of the first character of the printed text
(see PUT_TEXT_ALIGN_... though)
@param fface The font to use for the text
@param size Font size in pixels (by default) or pts
@param weight Font weight, 100..1000,
where 100 is "thin" font, 400 is "regular",
600 is "semibold", 800 is "bold" and beyond that is "black".
The default weight means "400" for variable-weight fonts or
whatever "default" weight the used font provides.
@param flags Various flags, see PUT_TEXT_...
@param wrap The optional text wrapping range; see #putText.
*/
CV_EXPORTS_W Rect getTextSize( Size imgsize, const String& text, Point org,
FontFace& fface, int size, int weight=0,
PutTextFlags flags=PUT_TEXT_ALIGN_LEFT, Range wrap=Range() );
/** @brief Line iterator
The class is used to iterate over all the pixels on the raster line

@ -1814,13 +1814,14 @@ public class ImgprocTest extends OpenCVTestCase {
double fontScale = 2;
int thickness = 3;
int baseLine[] = new int[1];
double EPS=5.0;
Imgproc.getTextSize(text, Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, thickness, null);
Size res = Imgproc.getTextSize(text, Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, thickness, baseLine);
assertEquals(543.0, res.width);
assertEquals(44.0, res.height);
assertEquals(20, baseLine[0]);
assertEquals(494.0, res.width, EPS);
assertEquals(51.0, res.height, EPS);
assertEquals(10, baseLine[0], 2.0);
}
public void testCircleMatPointIntScalar() {
@ -2032,7 +2033,7 @@ public class ImgprocTest extends OpenCVTestCase {
public void testPutTextMatStringPointIntDoubleScalar() {
String text = "Hello World";
Size labelSize = new Size(175, 22);
Size labelSize = new Size(170, 23);
Mat img = new Mat(20 + (int) labelSize.height, 20 + (int) labelSize.width, CvType.CV_8U, colorBlack);
Point origin = new Point(10, labelSize.height + 10);
@ -2040,13 +2041,13 @@ public class ImgprocTest extends OpenCVTestCase {
assertTrue(Core.countNonZero(img) > 0);
// check that border is not corrupted
Imgproc.rectangle(img, new Point(11, 11), new Point(labelSize.width + 10, labelSize.height + 10), colorBlack, Imgproc.FILLED);
Imgproc.rectangle(img, new Point(10, 10), new Point(labelSize.width + 10, labelSize.height + 10), colorBlack, Imgproc.FILLED);
assertEquals(0, Core.countNonZero(img));
}
public void testPutTextMatStringPointIntDoubleScalarInt() {
String text = "Hello World";
Size labelSize = new Size(176, 22);
Size labelSize = new Size(170, 23);
Mat img = new Mat(20 + (int) labelSize.height, 20 + (int) labelSize.width, CvType.CV_8U, colorBlack);
Point origin = new Point(10, labelSize.height + 10);
@ -2060,7 +2061,7 @@ public class ImgprocTest extends OpenCVTestCase {
public void testPutTextMatStringPointIntDoubleScalarIntIntBoolean() {
String text = "Hello World";
Size labelSize = new Size(175, 22);
Size labelSize = new Size(170, 23);
Mat img = new Mat(20 + (int) labelSize.height, 20 + (int) labelSize.width, CvType.CV_8U, colorBlack);
Point origin = new Point(10, 10);
@ -2069,7 +2070,7 @@ public class ImgprocTest extends OpenCVTestCase {
assertTrue(Core.countNonZero(img) > 0);
// check that border is not corrupted
Imgproc.rectangle(img, new Point(10, 10), new Point(labelSize.width + 9, labelSize.height + 9), colorBlack, Imgproc.FILLED);
Imgproc.rectangle(img, new Point(10, 10), new Point(labelSize.width + 10, labelSize.height + 10), colorBlack, Imgproc.FILLED);
assertEquals(0, Core.countNonZero(img));
}
}

@ -0,0 +1,38 @@
//
// FontFace.h
//
// Created by VP in 2020
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#else
#define CV_EXPORTS
#endif
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
CV_EXPORTS @interface FontFace : NSObject
@property(readonly) NSString* name;
#ifdef __cplusplus
@property(readonly) cv::FontFace& nativeRef;
#endif
-(instancetype)initWith:(const NSString*)name;
-(instancetype)init;
#ifdef __cplusplus
+(instancetype)fromNative:(cv::FontFace&)fface;
#endif
-(NSString *)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,43 @@
//
// FontFace.mm
//
// Created by VP in 2020.
//
#import "FontFace.h"
@implementation FontFace {
cv::FontFace native;
}
-(cv::FontFace&)nativeRef {
return native;
}
- (NSString*)name {
return [NSString stringWithUTF8String:native.getName().c_str()];
}
-(instancetype)init {
return [super init];
}
-(instancetype)initWith:(NSString*)name {
self = [super init];
if (self) {
self.nativeRef.set(std::string(name.UTF8String));
}
return self;
}
+(instancetype)fromNative:(cv::FontFace&)fface {
FontFace* ff = [[FontFace alloc] init];
ff.nativeRef = fface;
return ff;
}
- (NSString *)description {
return [NSString stringWithFormat:@"FontFace [name=%s]", self.nativeRef.getName().c_str()];
}
@end

@ -1,4 +1,7 @@
{
"class_ignore_list": [
"FontFace"
],
"enum_ignore_list" : [
"MorphShapes_c",
"SmoothMethod_c"
@ -125,5 +128,12 @@
"Subdiv2D" : {
"(void)insert:(NSArray<Point2f*>*)ptvec" : { "insert" : {"name" : "insertVector"} }
}
},
"type_dict": {
"FontFace": {
"objc_type": "FontFace*",
"to_cpp": "%(n)s.nativeRef",
"from_cpp": "[FontFace fromNative:%(n)s]"
}
}
}

@ -1490,13 +1490,14 @@ class ImgprocTest: OpenCVTestCase {
let fontScale:Int32 = 2
let thickness:Int32 = 3
var baseLine:Int32 = 0
let EPS = 0.0
Imgproc.getTextSize(text: text, fontFace: .FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale: Double(fontScale), thickness: thickness, baseLine: &baseLine)
let res = Imgproc.getTextSize(text: text, fontFace: .FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale: Double(fontScale), thickness: thickness, baseLine: &baseLine)
XCTAssertEqual(431, res.width)
XCTAssertEqual(44, res.height)
XCTAssertEqual(20, baseLine)
XCTAssertEqual(454, res.width, accuracy:EPS)
XCTAssertEqual(51, res.height, accuracy:EPS)
XCTAssertEqual(10, baseLine, accuracy:2.0)
}
func testCircleMatPointIntScalar() {
@ -1700,7 +1701,7 @@ class ImgprocTest: OpenCVTestCase {
func testPutTextMatStringPointIntDoubleScalar() {
let text = "Hello World"
let labelSize = Size(width: 175, height: 22)
let labelSize = Size(width: 170, height: 23)
let img = Mat(rows: 20 + labelSize.height, cols: 20 + labelSize.width, type: CvType.CV_8U, scalar: colorBlack)
let origin = Point(x: 10, y: labelSize.height + 10)
@ -1708,13 +1709,13 @@ class ImgprocTest: OpenCVTestCase {
XCTAssert(Core.countNonZero(src: img) > 0)
// check that border is not corrupted
Imgproc.rectangle(img: img, pt1: Point(x: 11, y: 11), pt2: Point(x: labelSize.width + 10, y: labelSize.height + 10), color: colorBlack, thickness: Core.FILLED)
Imgproc.rectangle(img: img, pt1: Point(x: 10, y: 10), pt2: Point(x: labelSize.width + 10, y: labelSize.height + 10), color: colorBlack, thickness: Core.FILLED)
XCTAssertEqual(0, Core.countNonZero(src: img))
}
func testPutTextMatStringPointIntDoubleScalarInt() {
let text = "Hello World"
let labelSize = Size(width: 176, height: 22)
let labelSize = Size(width: 170, height: 23)
let img = Mat(rows: 20 + labelSize.height, cols: 20 + labelSize.width, type: CvType.CV_8U, scalar: colorBlack)
let origin = Point(x: 10, y: labelSize.height + 10)
@ -1728,7 +1729,7 @@ class ImgprocTest: OpenCVTestCase {
func testPutTextMatStringPointIntDoubleScalarIntIntBoolean() {
let text = "Hello World"
let labelSize = Size(width: 175, height: 22)
let labelSize = Size(width: 170, height: 23)
let img = Mat(rows: 20 + labelSize.height, cols: 20 + labelSize.width, type: CvType.CV_8U, scalar: colorBlack)
let origin = Point(x: 10, y: 10)

@ -2037,331 +2037,6 @@ void polylines( InputOutputArray _img, const Point* const* pts, const int* npts,
}
}
enum { FONT_SIZE_SHIFT=8, FONT_ITALIC_ALPHA=(1 << 8),
FONT_ITALIC_DIGIT=(2 << 8), FONT_ITALIC_PUNCT=(4 << 8),
FONT_ITALIC_BRACES=(8 << 8), FONT_HAVE_GREEK=(16 << 8),
FONT_HAVE_CYRILLIC=(32 << 8) };
static const int HersheyPlain[] = {
(5 + 4*16) + FONT_HAVE_GREEK,
199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
215, 190, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 193, 84,
194, 85, 86, 87, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
195, 223, 196, 88 };
static const int HersheyPlainItalic[] = {
(5 + 4*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
215, 190, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 193, 84,
194, 85, 86, 87, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161,
162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
195, 223, 196, 88 };
static const int HersheyComplexSmall[] = {
(6 + 7*16) + FONT_HAVE_GREEK,
1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 2213, 1241, 1238, 1242,
1215, 1273, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013,
1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1223, 1084,
1224, 1247, 586, 1249, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126,
1225, 1229, 1226, 1246 };
static const int HersheyComplexSmallItalic[] = {
(6 + 7*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 1213, 1241, 1238, 1242,
1215, 1273, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063,
1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1223, 1084,
1224, 1247, 586, 1249, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161,
1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176,
1225, 1229, 1226, 1246 };
static const int HersheySimplex[] = {
(9 + 12*16) + FONT_HAVE_GREEK,
2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
715, 690, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513,
514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 693, 584,
694, 2247, 586, 2249, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611,
612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626,
695, 723, 696, 2246 };
static const int HersheyDuplex[] = {
(9 + 12*16) + FONT_HAVE_GREEK,
2199, 2714, 2728, 2732, 2719, 2733, 2718, 2727, 2721, 2722, 2723, 2725, 2711, 2724, 2710, 2720,
2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2712, 2713, 2730, 2726, 2731,
2715, 2734, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513,
2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2223, 2084,
2224, 2247, 587, 2249, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611,
2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626,
2225, 2229, 2226, 2246 };
static const int HersheyComplex[] = {
(9 + 12*16) + FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC,
2199, 2214, 2217, 2275, 2274, 2271, 2272, 2216, 2221, 2222, 2219, 2232, 2211, 2231, 2210, 2220,
2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2212, 2213, 2241, 2238, 2242,
2215, 2273, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2223, 2084,
2224, 2247, 587, 2249, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111,
2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126,
2225, 2229, 2226, 2246, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811,
2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824, 2825, 2826,
2827, 2828, 2829, 2830, 2831, 2832, 2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909,
2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924,
2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932};
static const int HersheyComplexItalic[] = {
(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT +
FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC,
2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
2765, 2273, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063,
2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2223, 2084,
2224, 2247, 587, 2249, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161,
2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176,
2225, 2229, 2226, 2246 };
static const int HersheyTriplex[] = {
(9 + 12*16) + FONT_HAVE_GREEK,
2199, 3214, 3228, 3232, 3219, 3233, 3218, 3227, 3221, 3222, 3223, 3225, 3211, 3224, 3210, 3220,
3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3212, 3213, 3230, 3226, 3231,
3215, 3234, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013,
2014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 2223, 2084,
2224, 2247, 587, 2249, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111,
3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126,
2225, 2229, 2226, 2246 };
static const int HersheyTriplexItalic[] = {
(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT +
FONT_ITALIC_PUNCT + FONT_HAVE_GREEK,
2199, 3264, 3278, 3282, 3269, 3233, 3268, 3277, 3271, 3272, 3223, 3225, 3261, 3224, 3260, 3270,
3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3262, 3263, 3230, 3226, 3231,
3265, 3234, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063,
2064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 2223, 2084,
2224, 2247, 587, 2249, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161,
3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176,
2225, 2229, 2226, 2246 };
static const int HersheyScriptSimplex[] = {
(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
715, 690, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 693, 584,
694, 2247, 586, 2249, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661,
662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676,
695, 723, 696, 2246 };
static const int HersheyScriptComplex[] = {
(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT + FONT_HAVE_GREEK,
2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
2215, 2273, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563,
2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2223, 2084,
2224, 2247, 586, 2249, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661,
2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676,
2225, 2229, 2226, 2246 };
static const int* getFontData(int fontFace)
{
bool isItalic = (fontFace & FONT_ITALIC) != 0;
const int* ascii = 0;
switch( fontFace & 15 )
{
case FONT_HERSHEY_SIMPLEX:
ascii = HersheySimplex;
break;
case FONT_HERSHEY_PLAIN:
ascii = !isItalic ? HersheyPlain : HersheyPlainItalic;
break;
case FONT_HERSHEY_DUPLEX:
ascii = HersheyDuplex;
break;
case FONT_HERSHEY_COMPLEX:
ascii = !isItalic ? HersheyComplex : HersheyComplexItalic;
break;
case FONT_HERSHEY_TRIPLEX:
ascii = !isItalic ? HersheyTriplex : HersheyTriplexItalic;
break;
case FONT_HERSHEY_COMPLEX_SMALL:
ascii = !isItalic ? HersheyComplexSmall : HersheyComplexSmallItalic;
break;
case FONT_HERSHEY_SCRIPT_SIMPLEX:
ascii = HersheyScriptSimplex;
break;
case FONT_HERSHEY_SCRIPT_COMPLEX:
ascii = HersheyScriptComplex;
break;
default:
CV_Error( CV_StsOutOfRange, "Unknown font type" );
}
return ascii;
}
inline void readCheck(int &c, int &i, const String &text, int fontFace)
{
int leftBoundary = ' ', rightBoundary = 127;
if(c >= 0x80 && fontFace == FONT_HERSHEY_COMPLEX)
{
if(c == 0xD0 && (uchar)text[i + 1] >= 0x90 && (uchar)text[i + 1] <= 0xBF)
{
c = (uchar)text[++i] - 17;
leftBoundary = 127;
rightBoundary = 175;
}
else if(c == 0xD1 && (uchar)text[i + 1] >= 0x80 && (uchar)text[i + 1] <= 0x8F)
{
c = (uchar)text[++i] + 47;
leftBoundary = 175;
rightBoundary = 191;
}
else
{
if(c >= 0xC0 && text[i+1] != 0) //2 bytes utf
i++;
if(c >= 0xE0 && text[i+1] != 0) //3 bytes utf
i++;
if(c >= 0xF0 && text[i+1] != 0) //4 bytes utf
i++;
if(c >= 0xF8 && text[i+1] != 0) //5 bytes utf
i++;
if(c >= 0xFC && text[i+1] != 0) //6 bytes utf
i++;
c = '?';
}
}
if(c >= rightBoundary || c < leftBoundary)
c = '?';
}
extern const char* g_HersheyGlyphs[];
void putText( InputOutputArray _img, const String& text, Point org,
int fontFace, double fontScale, Scalar color,
int thickness, int line_type, bool bottomLeftOrigin )
{
CV_INSTRUMENT_REGION();
if ( text.empty() )
{
return;
}
Mat img = _img.getMat();
const int* ascii = getFontData(fontFace);
double buf[4];
scalarToRawData(color, buf, img.type(), 0);
int base_line = -(ascii[0] & 15);
int hscale = cvRound(fontScale*XY_ONE), vscale = hscale;
if( line_type == CV_AA && img.depth() != CV_8U )
line_type = 8;
if( bottomLeftOrigin )
vscale = -vscale;
int64 view_x = (int64)org.x << XY_SHIFT;
int64 view_y = ((int64)org.y << XY_SHIFT) + base_line*vscale;
std::vector<Point2l> pts;
pts.reserve(1 << 10);
const char **faces = cv::g_HersheyGlyphs;
for( int i = 0; i < (int)text.size(); i++ )
{
int c = (uchar)text[i];
Point2l p;
readCheck(c, i, text, fontFace);
const char* ptr = faces[ascii[(c-' ')+1]];
p.x = (uchar)ptr[0] - 'R';
p.y = (uchar)ptr[1] - 'R';
int64 dx = p.y*hscale;
view_x -= p.x*hscale;
pts.resize(0);
for( ptr += 2;; )
{
if( *ptr == ' ' || !*ptr )
{
if( pts.size() > 1 )
PolyLine( img, &pts[0], (int)pts.size(), false, buf, thickness, line_type, XY_SHIFT );
if( !*ptr++ )
break;
pts.resize(0);
}
else
{
p.x = (uchar)ptr[0] - 'R';
p.y = (uchar)ptr[1] - 'R';
ptr += 2;
pts.push_back(Point2l(p.x*hscale + view_x, p.y*vscale + view_y));
}
}
view_x += dx;
}
}
Size getTextSize( const String& text, int fontFace, double fontScale, int thickness, int* _base_line)
{
Size size;
double view_x = 0;
const char **faces = cv::g_HersheyGlyphs;
const int* ascii = getFontData(fontFace);
int base_line = (ascii[0] & 15);
int cap_line = (ascii[0] >> 4) & 15;
size.height = cvRound((cap_line + base_line)*fontScale + (thickness+1)/2);
for( int i = 0; i < (int)text.size(); i++ )
{
int c = (uchar)text[i];
Point p;
readCheck(c, i, text, fontFace);
const char* ptr = faces[ascii[(c-' ')+1]];
p.x = (uchar)ptr[0] - 'R';
p.y = (uchar)ptr[1] - 'R';
view_x += (p.y - p.x)*fontScale;
}
size.width = cvRound(view_x + thickness);
if( _base_line )
*_base_line = cvRound(base_line*fontScale + thickness*0.5);
return size;
}
double getFontScaleFromHeight(const int fontFace, const int pixelHeight, const int thickness)
{
// By https://stackoverflow.com/a/27898487/1531708
const int* ascii = getFontData(fontFace);
int base_line = (ascii[0] & 15);
int cap_line = (ascii[0] >> 4) & 15;
return static_cast<double>(pixelHeight - static_cast<double>((thickness + 1)) / 2.0) / static_cast<double>(cap_line + base_line);
}
}
void cv::fillConvexPoly(InputOutputArray img, InputArray _points,
@ -2861,7 +2536,7 @@ cvInitFont( CvFont *font, int font_face, double hscale, double vscale,
{
CV_Assert( font != 0 && hscale > 0 && vscale > 0 && thickness >= 0 );
font->ascii = cv::getFontData(font_face);
font->ascii = 0;
font->font_face = font_face;
font->hscale = (float)hscale;
font->vscale = (float)vscale;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,692 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// This is refactored (and split into 2 files) version of stb_truetype.h
// from https://github.com/nothings/stb.
// Support for variable fonts has been added and
// a few other modifications & optimizations have been done.
//////////////// Below is the original copyright information /////////////////
///////// (btw, OpenCV chooses the option A (MIT) for the license) ///////////
// Authored from 2009-2020 by Sean Barrett / RAD Game Tools.
// See stb_truetype.cpp for the details
/*
------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------
*/
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
////
//// INTERFACE
////
////
#ifndef __STB_INCLUDE_STB_TRUETYPE_HPP__
#define __STB_INCLUDE_STB_TRUETYPE_HPP__
#if 0 //def STBTT_STATIC
#define STBTT_DEF static
#else
#define STBTT_DEF extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define STBTT_FOURCC(a, b, c, d) \
(unsigned)((((unsigned char)(a)) << 24) | \
(((unsigned char)(b)) << 16) | \
(((unsigned char)(c)) << 8) | \
((unsigned char)(d)))
// private structure
typedef struct
{
unsigned char *data;
int cursor;
int size;
} stbtt__buf;
//////////////////////////////////////////////////////////////////////////////
//
// TEXTURE BAKING API
//
// If you use this API, you only have to call two functions ever.
//
typedef struct
{
unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
float xoff,yoff,xadvance;
} stbtt_bakedchar;
STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf)
float pixel_height, // height of font in pixels
unsigned char *pixels, int pw, int ph, // bitmap to be filled in
int first_char, int num_chars, // characters to bake
stbtt_bakedchar *chardata); // you allocate this, it's num_chars long
// if return is positive, the first unused row of the bitmap
// if return is negative, returns the negative of the number of characters that fit
// if return is 0, no characters fit and no rows were used
// This uses a very crappy packing.
typedef struct
{
float x0,y0,s0,t0; // top-left
float x1,y1,s1,t1; // bottom-right
} stbtt_aligned_quad;
STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above
int char_index, // character to display
float *xpos, float *ypos, // pointers to current position in screen pixel space
stbtt_aligned_quad *q, // output: quad to draw
int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier
// Call GetBakedQuad with char_index = 'character - first_char', and it
// creates the quad you need to draw and advances the current position.
//
// The coordinate system used assumes y increases downwards.
//
// Characters will extend both above and below the current position;
// see discussion of "BASELINE" above.
//
// It's inefficient; you might want to c&p it and optimize it.
STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);
// Query the font vertical metrics without having to create a font first.
//////////////////////////////////////////////////////////////////////////////
//
// NEW TEXTURE BAKING API
//
// This provides options for packing multiple fonts into one atlas, not
// perfectly but better than nothing.
typedef struct
{
unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
float xoff,yoff,xadvance;
float xoff2,yoff2;
} stbtt_packedchar;
typedef struct stbtt_pack_context stbtt_pack_context;
typedef struct stbtt_fontinfo stbtt_fontinfo;
#ifndef STB_RECT_PACK_VERSION
typedef struct stbrp_rect stbrp_rect;
#endif
STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
// Initializes a packing context stored in the passed-in stbtt_pack_context.
// Future calls using this context will pack characters into the bitmap passed
// in here: a 1-channel bitmap that is width * height. stride_in_bytes is
// the distance from one row to the next (or 0 to mean they are packed tightly
// together). "padding" is the amount of padding to leave between each
// character (normally you want '1' for bitmaps you'll use as textures with
// bilinear filtering).
//
// Returns 0 on failure, 1 on success.
STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc);
// Cleans up the packing context and frees all memory.
#define STBTT_POINT_SIZE(x) (-(x))
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
// Creates character bitmaps from the font_index'th font found in fontdata (use
// font_index=0 if you don't know what that is). It creates num_chars_in_range
// bitmaps for characters with unicode values starting at first_unicode_char_in_range
// and increasing. Data for how to render them is stored in chardata_for_range;
// pass these to stbtt_GetPackedQuad to get back renderable quads.
//
// font_size is the full height of the character from ascender to descender,
// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed
// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()
// and pass that result as 'font_size':
// ..., 20 , ... // font max minus min y is 20 pixels tall
// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall
typedef struct
{
float font_size;
int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint
int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints
int num_chars;
stbtt_packedchar *chardata_for_range; // output
unsigned char h_oversample, v_oversample; // don't set these, they're used internally
} stbtt_pack_range;
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
// Creates character bitmaps from multiple ranges of characters stored in
// ranges. This will usually create a better-packed bitmap than multiple
// calls to stbtt_PackFontRange. Note that you can call this multiple
// times within a single PackBegin/PackEnd.
STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);
// Oversampling a font increases the quality by allowing higher-quality subpixel
// positioning, and is especially valuable at smaller text sizes.
//
// This function sets the amount of oversampling for all following calls to
// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given
// pack context. The default (no oversampling) is achieved by h_oversample=1
// and v_oversample=1. The total number of pixels required is
// h_oversample*v_oversample larger than the default; for example, 2x2
// oversampling requires 4x the storage of 1x1. For best results, render
// oversampled textures with bilinear filtering. Look at the readme in
// stb/tests/oversample for information about oversampled fonts
//
// To use with PackFontRangesGather etc., you must set it before calls
// call to PackFontRangesGatherRects.
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
// If skip != 0, this tells stb_truetype to skip any codepoints for which
// there is no corresponding glyph. If skip=0, which is the default, then
// codepoints without a glyph recived the font's "missing character" glyph,
// typically an empty box by convention.
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
int char_index, // character to display
float *xpos, float *ypos, // pointers to current position in screen pixel space
stbtt_aligned_quad *q, // output: quad to draw
int align_to_integer);
STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
// Calling these functions in sequence is roughly equivalent to calling
// stbtt_PackFontRanges(). If you more control over the packing of multiple
// fonts, or if you want to pack custom data into a font texture, take a look
// at the source to of stbtt_PackFontRanges() and create a custom version
// using these functions, e.g. call GatherRects multiple times,
// building up a single array of rects, then call PackRects once,
// then call RenderIntoRects repeatedly. This may result in a
// better packing than calling PackFontRanges multiple times
// (or it may not).
// this is an opaque structure that you shouldn't mess with which holds
// all the context needed from PackBegin to PackEnd.
struct stbtt_pack_context {
void *user_allocator_context;
void *pack_info;
int width;
int height;
int stride_in_bytes;
int padding;
int skip_missing;
unsigned int h_oversample, v_oversample;
unsigned char *pixels;
void *nodes;
};
//////////////////////////////////////////////////////////////////////////////
//
// FONT LOADING
//
//
STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);
// This function will determine the number of fonts in a font file. TrueType
// collection (.ttc) files may contain multiple fonts, while TrueType font
// (.ttf) files only contain one font. The number of fonts can be used for
// indexing with the previous function where the index is between zero and one
// less than the total fonts. If an error occurs, -1 is returned.
STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
// Each .ttf/.ttc file may have more than one font. Each font has a sequential
// index number starting from 0. Call this function to get the font offset for
// a given index; it returns -1 if the index is out of range. A regular .ttf
// file will only define one font and it always be at offset 0, so it will
// return '0' for index 0, and -1 for all other indices.
#ifndef STBTT_MAX_AXES
#define STBTT_MAX_AXES 16
#endif
typedef struct stbtt_axisinfo
{
int tag;
int minval, defval, maxval;
int currval;
} stbtt_axisinfo;
// The following structure is defined publicly so you can declare one on
// the stack or as a global or etc, but you should treat it as opaque.
struct stbtt_fontinfo
{
void * userdata;
unsigned char * data; // pointer to .ttf file
unsigned char * dataend; // data + size
int fontstart; // offset of start of font
unsigned size; // the data buffer size
int numGlyphs; // number of glyphs, needed for range checking
int loca,head,glyf,hhea,hmtx,kern,gpos,svg,avar,fvar,gvar,hvar; // table locations as offset from start of .ttf
int index_map; // a cmap mapping for our chosen character encoding
int indexToLocFormat; // format needed to map from glyph index to glyph
int axis_count; // the number of variable font axes
stbtt_axisinfo axes[STBTT_MAX_AXES]; // information about each axis
short axes_normvalues[STBTT_MAX_AXES]; // normalized (within [-1, 1]) coordinates of
// the currently used variation. They are already transformed
// using avar (if any)
int gvar_shared_count; // the number of shared tuples, used by 'gvar'
int gvar_shared_tuples; // offset of the shared tuples
int gvar_glob_offset; // the global offset of glyph variations table
int gvar_glyph_offsets; // the relative offsets of glyph variations
int gvar_off_format; // true if offsets are 32-bit
stbtt__buf cff; // cff font data
stbtt__buf charstrings; // the charstring index
stbtt__buf gsubrs; // global charstring subroutines index
stbtt__buf subrs; // private charstring subroutines index
stbtt__buf fontdicts; // array of font dicts
stbtt__buf fdselect; // map from glyph to fontdict
};
STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
// Given an offset into the file that defines a font, this function builds
// the necessary cached info for the rest of the system. You must allocate
// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
// need to do anything special to free it, because the contents are pure
// value data with no additional data structures. Returns 0 on failure.
STBTT_DEF int stbtt_InitFont2(stbtt_fontinfo *info, const unsigned char *data, unsigned size, int offset);
// Same as stbtt_InitFont, but also takes the size of "data" buffer,
// in order to control and avoid out of range accesses.
STBTT_DEF stbtt_fontinfo* stbtt_CreateFont(const unsigned char *data, unsigned size, int offset);
// Allocates font structure and initializes it. Returns 0 if there was an error.
STBTT_DEF void stbtt_ReleaseFont(stbtt_fontinfo **info);
// Allocates font structure and initializes it. Returns 0 if there was an error.
//////////////////////////////////////////////////////////////////////////////
//
// CHARACTER TO GLYPH-INDEX CONVERSIOn
STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);
// If you're going to perform multiple operations on the same character
// and you want a speed-up, call this function with the character you're
// going to process, then use glyph-based functions instead of the
// codepoint-based functions.
// Returns 0 if the character codepoint is not defined in the font.
//////////////////////////////////////////////////////////////////////////////
//
// CHARACTER PROPERTIES
//
STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);
// computes a scale factor to produce a font whose "height" is 'pixels' tall.
// Height is measured as the distance from the highest ascender to the lowest
// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
// and computing:
// scale = pixels / (ascent - descent)
// so if you prefer to measure height by the ascent only, use a similar calculation.
STBTT_DEF float stbtt_ScaleForPixelHeightNoDesc(const stbtt_fontinfo *info, float height);
STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);
// computes a scale factor to produce a font whose EM size is mapped to
// 'pixels' tall. This is probably what traditional APIs compute, but
// I'm not positive.
STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);
// ascent is the coordinate above the baseline the font extends; descent
// is the coordinate below the baseline the font extends (i.e. it is typically negative)
// lineGap is the spacing between one row's descent and the next row's ascent...
// so you should advance the vertical position by "*ascent - *descent + *lineGap"
// these are expressed in unscaled coordinates, so you must multiply by
// the scale factor for a given size
STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);
// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
// table (specific to MS/Windows TTF files).
//
// Returns 1 on success (table present), 0 on failure.
STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
// the bounding box around all possible characters
STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);
// leftSideBearing is the offset from the current horizontal position to the left edge of the character
// advanceWidth is the offset from the current horizontal position to the next horizontal position
// these are expressed in unscaled coordinates
STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);
// an additional amount to add to the 'advance' value between ch1 and ch2
STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);
// Gets the bounding box of the visible part of the glyph, in unscaled coordinates
STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);
STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);
STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
STBTT_DEF void stbtt__ScaleGlyphBox(int ix0, int iy0, int ix1, int iy1,
float scale_x, float scale_y, float shift_x, float shift_y,
int *out_ix0, int *out_iy0, int *out_ix1, int *out_iy1);
// as above, but takes one or more glyph indices for greater efficiency
typedef struct stbtt_kerningentry
{
int glyph1; // use stbtt_FindGlyphIndex
int glyph2;
int advance;
} stbtt_kerningentry;
STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info);
STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);
// Retrieves a complete list of all of the kerning pairs provided by the font
// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write.
// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1)
//////////////////////////////////////////////////////////////////////////////
//
// GLYPH SHAPES (you probably don't need these, but they have to go before
// the bitmaps for C declaration-order reasons)
//
#ifndef STBTT_vmove // you can predefine these to use different values (but why?)
enum {
STBTT_vmove=1,
STBTT_vline,
STBTT_vcurve,
STBTT_vcubic
};
#endif
#ifndef stbtt_vertex // you can predefine this to use different values
// (we share this with other code at RAD)
#define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
typedef struct
{
stbtt_vertex_type x,y,cx,cy,cx1,cy1;
unsigned char type,padding;
} stbtt_vertex;
#endif
STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);
// returns non-zero if nothing is drawn for this glyph
STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint,
stbtt_vertex **vertices, int* ix0, int* iy0, int* ix1, int* iy1);
STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices,
int* ix0, int* iy0, int* ix1, int* iy1);
// returns # of vertices and fills *vertices with the pointer to them
// these are expressed in "unscaled" coordinates
//
// The shape is a series of contours. Each one starts with
// a STBTT_moveto, then consists of a series of mixed
// STBTT_lineto and STBTT_curveto segments. A lineto
// draws a line from previous endpoint to its x,y; a curveto
// draws a quadratic bezier from previous endpoint to
// its x,y, using cx,cy as the bezier control point.
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
// frees the data allocated above
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
// fills svg with the character's SVG data.
// returns data size or 0 if SVG not found.
//////////////////////////////////////////////////////////////////////////////
//
// FONT VARIATIONS
//
STBTT_DEF int stbtt_GetWeight(const stbtt_fontinfo* info);
STBTT_DEF int stbtt_GetInstance(const stbtt_fontinfo* info, stbtt_axisinfo* axes, int max_count);
STBTT_DEF int stbtt_SetInstance(stbtt_fontinfo* info, const int* params, int count, int reset_to_defaults);
//////////////////////////////////////////////////////////////////////////////
//
// BITMAP RENDERING
//
STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);
// frees the bitmap allocated below
STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
// get the bbox of the bitmap centered around the glyph origin; so the
// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
// the bitmap top left is (leftSideBearing*scale,iy0).
// (Note that the bitmap uses y-increases-down, but the shape uses
// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
// shift for the character
// the following functions are equivalent to the above functions, but operate
// on glyph indices instead of Unicode codepoints (for efficiency)
STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixelRealloc(const stbtt_fontinfo *info, float scale_x, float scale_y,
float shift_x, float shift_y,
int glyph, int *width, int *height, int* step,
int *xoff, int *yoff, float* advx,
unsigned char** buf, int* bufsize);
STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);
STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
// @TODO: don't expose this structure
typedef struct
{
int w,h,stride;
unsigned char *pixels;
} stbtt__bitmap;
// rasterize a shape with quadratic beziers into a bitmap
STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into
float flatness_in_pixels, // allowable error of curve in pixels
stbtt_vertex *vertices, // array of vertices defining shape
int num_verts, // number of vertices in above array
float scale_x, float scale_y, // scale applied to input vertices
float shift_x, float shift_y, // translation applied to input vertices
int x_off, int y_off, // another translation applied to input
int invert, // if non-zero, vertically flip shape
void *userdata); // context for to STBTT_MALLOC
//////////////////////////////////////////////////////////////////////////////
//
// Signed Distance Function (or Field) rendering
STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);
// frees the SDF bitmap allocated below
STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
// These functions compute a discretized SDF field for a single character, suitable for storing
// in a single-channel texture, sampling with bilinear filtering, and testing against
// larger than some threshold to produce scalable fonts.
// info -- the font
// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
// glyph/codepoint -- the character to generate the SDF for
// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0),
// which allows effects like bit outlines
// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
// if positive, > onedge_value is inside; if negative, < onedge_value is inside
// width,height -- output height & width of the SDF bitmap (including padding)
// xoff,yoff -- output origin of the character
// return value -- a 2D array of bytes 0..255, width*height in size
//
// pixel_dist_scale & onedge_value are a scale & bias that allows you to make
// optimal use of the limited 0..255 for your application, trading off precision
// and special effects. SDF values outside the range 0..255 are clamped to 0..255.
//
// Example:
// scale = stbtt_ScaleForPixelHeight(22)
// padding = 5
// onedge_value = 180
// pixel_dist_scale = 180/5.0 = 36.0
//
// This will create an SDF bitmap in which the character is about 22 pixels
// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
// shape, sample the SDF at each pixel and fill the pixel if the SDF value
// is greater than or equal to 180/255. (You'll actually want to antialias,
// which is beyond the scope of this example.) Additionally, you can compute
// offset outlines (e.g. to stroke the character border inside & outside,
// or only outside). For example, to fill outside the character up to 3 SDF
// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
// choice of variables maps a range from 5 pixels outside the shape to
// 2 pixels inside the shape to 0..255; this is intended primarily for apply
// outside effects only (the interior range is needed to allow proper
// antialiasing of the font at *smaller* sizes)
//
// The function computes the SDF analytically at each SDF pixel, not by e.g.
// building a higher-res bitmap and approximating it. In theory the quality
// should be as high as possible for an SDF of this size & representation, but
// unclear if this is true in practice (perhaps building a higher-res bitmap
// and computing from that can allow drop-out prevention).
//
// The algorithm has not been optimized at all, so expect it to be slow
// if computing lots of characters or very large sizes.
//////////////////////////////////////////////////////////////////////////////
//
// Finding the right font...
//
// You should really just solve this offline, keep your own tables
// of what font is what, and don't try to get it out of the .ttf file.
// That's because getting it out of the .ttf file is really hard, because
// the names in the file can appear in many possible encodings, in many
// possible languages, and e.g. if you need a case-insensitive comparison,
// the details of that depend on the encoding & language in a complex way
// (actually underspecified in truetype, but also gigantic).
//
// But you can use the provided functions in two possible ways:
// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
// unicode-encoded names to try to find the font you want;
// you can run this before calling stbtt_InitFont()
//
// stbtt_GetFontNameString() lets you get any of the various strings
// from the file yourself and do your own comparisons on them.
// You have to have called stbtt_InitFont() first.
STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);
// returns the offset (not index) of the font that matches, or -1 if none
// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
// if you use any other flag, use a font name like "Arial"; this checks
// the 'macStyle' header field; i don't know if fonts set this consistently
#define STBTT_MACSTYLE_DONTCARE 0
#define STBTT_MACSTYLE_BOLD 1
#define STBTT_MACSTYLE_ITALIC 2
#define STBTT_MACSTYLE_UNDERSCORE 4
#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0
STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);
// returns 1/0 whether the first string interpreted as utf8 is identical to
// the second string interpreted as big-endian utf16... useful for strings from next func
STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
// returns the string (which may be big-endian double byte, e.g. for unicode)
// and puts the length in bytes in *length.
//
// some of the values for the IDs are below; for more see the truetype spec:
// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
// http://www.microsoft.com/typography/otspec/name.htm
enum { // platformID
STBTT_PLATFORM_ID_UNICODE =0,
STBTT_PLATFORM_ID_MAC =1,
STBTT_PLATFORM_ID_ISO =2,
STBTT_PLATFORM_ID_MICROSOFT =3
};
enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
STBTT_UNICODE_EID_UNICODE_1_0 =0,
STBTT_UNICODE_EID_UNICODE_1_1 =1,
STBTT_UNICODE_EID_ISO_10646 =2,
STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,
STBTT_UNICODE_EID_UNICODE_2_0_FULL=4
};
enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
STBTT_MS_EID_SYMBOL =0,
STBTT_MS_EID_UNICODE_BMP =1,
STBTT_MS_EID_SHIFTJIS =2,
STBTT_MS_EID_UNICODE_FULL =10
};
enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4,
STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5,
STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6,
STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7
};
enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
// problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410,
STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411,
STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412,
STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419,
STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409,
STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D
};
enum { // languageID for STBTT_PLATFORM_ID_MAC
STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11,
STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23,
STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32,
STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 ,
STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 ,
STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,
STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19
};
#ifdef __cplusplus
}
#endif
#endif // __STB_INCLUDE_STB_TRUETYPE_H__

@ -86,6 +86,9 @@ void CV_DrawingTest::run( int )
float Eps = 1;
if( err > Eps)
{
//imshow("reference", valImg);
//imshow("result", testImg);
//waitKey();
ts->printf( ts->LOG, "NORM_L1 between testImg and valImg is equal %f (larger than %f)\n", err, Eps );
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
}
@ -619,8 +622,17 @@ TEST(Drawing, putText_no_garbage)
EXPECT_EQ(0, cv::countNonZero(mat(Rect(0, 0, 10, sz.height))));
EXPECT_EQ(0, cv::countNonZero(mat(Rect(sz.width-10, 0, 10, sz.height))));
EXPECT_EQ(0, cv::countNonZero(mat(Rect(205, 0, 10, sz.height))));
EXPECT_EQ(0, cv::countNonZero(mat(Rect(405, 0, 10, sz.height))));
EXPECT_EQ(0, cv::countNonZero(mat(Rect(190, 0, 10, sz.height))));
EXPECT_EQ(0, cv::countNonZero(mat(Rect(380, 0, 10, sz.height))));
#if 0
rectangle(mat, Rect(0, 0, 10, sz.height), Scalar::all(255), 1, LINE_8);
rectangle(mat, Rect(sz.width-10, 0, 10, sz.height), Scalar::all(255), 1, LINE_8);
rectangle(mat, Rect(190, 0, 10, sz.height), Scalar::all(255), 1, LINE_8);
rectangle(mat, Rect(380, 0, 10, sz.height), Scalar::all(255), 1, LINE_8);
imshow("result", mat);
waitKey();
#endif
}
@ -679,4 +691,169 @@ TEST(Drawing, fillpoly_circle)
EXPECT_LT(diff_fp3, 1.);
}
TEST(Drawing, fromJava_getTextSize)
{
String text = "Android all the way";
double fontScale = 2;
int thickness = 3;
int baseLine = 0;
Size res0 = getTextSize(text, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, thickness, 0);
Size res = getTextSize(text, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, thickness, &baseLine);
#if 0
Mat img(200, 700, CV_8UC3, Scalar::all(255));
Point org(100, 100);
putText(img, text, org, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, Scalar(128, 0, 0), thickness);
rectangle(img, org, Point(org.x + res0.width, org.y - res0.height), Scalar(0, 0, 128), 2, LINE_AA);
imshow("result", img);
waitKey();
#endif
EXPECT_EQ(res0.width, res.width);
EXPECT_EQ(res0.height, res.height);
EXPECT_NEAR(494, res.width, 3.0);
EXPECT_NEAR(51, res.height, 3.0);
EXPECT_NEAR(10, baseLine, 3.0);
}
TEST(Drawing, fromJava_testPutTextMatStringPointIntDoubleScalarIntIntBoolean)
{
String text = "Hello World";
Size labelSize(170, 23);
Mat img(20 + (int)labelSize.height, 20 + (int)labelSize.width, CV_8U, Scalar::all(0));
Point origin(10, 10);
putText(img, text, origin, FONT_HERSHEY_SIMPLEX, 1.0, Scalar::all(255), 1, LINE_8, true);
EXPECT_LT(0, countNonZero(img));
// check that border is not corrupted
rectangle(img, origin,
Point(origin.x + labelSize.width, origin.y + labelSize.height),
Scalar::all(0), -1, 8);
//imshow("img", img);
//waitKey();
EXPECT_EQ(0, countNonZero(img));
origin = Point(10, labelSize.height + 10);
putText(img, text, origin, FONT_HERSHEY_SIMPLEX, 1.0, Scalar::all(255));
EXPECT_LT(0, countNonZero(img));
// check that border is not corrupted
rectangle(img, Point(10, 10), Point(labelSize.width + 10, labelSize.height + 10), Scalar::all(0), -1);
EXPECT_EQ(0, countNonZero(img));
}
typedef struct TextProp
{
const char* str;
bool ralign;
int weight;
bool italic;
} TextProp;
#ifdef HAVE_UNIFONT // there are other tests for text drawing, so the functionality is tested anyway,
// but this test needs concrete unicode font to compare the printed text
// (including CJK characters) with the reference picture from the database
TEST(Drawing, ttf_text)
{
string ts_data_path = TS::ptr()->get_data_path();
string custom_font_path = ts_data_path + "../highgui/drawing/";
FontFace sans("sans");
FontFace italic("italic");
Mat img(600, 1300, CV_8UC3);
TextProp text[] =
{
{"The quick brown fox jumps over lazy dog. Fly, start, finish, shuffle shuttle.", false, 400, false},
{"vechicle #5 detected; fps=123.45.\n", false, 600, false},
{"Съешь же ещё этих мягких французских булок, да выпей чаю!\n"
"Dès Noël où un zéphyr haï me vêt de glaçons würmiens je dîne\nd’exquis rôtis de bœuf au kir à l’aÿ d’âge mûr & cætera!\n"
"“Falsches Üben von Xylophonmusik quält jeden größeren Zwerg”.", false, 400, true},
{"¡Oh tú, sabio encantador, quienquiera que seas,\n"
"a quien ha de tocar el ser coronista desta peregrina\n"
"historia, ruégote que no te olvides de mi buen Rocinante,\n"
"compañero eterno mío en todos mis caminos y carreras!\n", false, 300, false},
{"Ταχίστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός.", false, 400, false},
{"春眠不觉晓,\n处处闻啼鸟。\n夜来风雨声,\n花落知多少。\n"
" あなたはそれが困難見つけた場合 — あなたは正しい方向に向かっている。\n"
" 넌 모든 꽃들을 다 꺾어버릴 수는 있겠지만, 봄이 오는 걸 막을 수는 없어。 ", false, 400, false}
};
Scalar color(150, 80, 0);
for(int iter = 0; iter < 1; iter++)
{
//double ts = (double)getTickCount();
img.setTo(Scalar::all(255));
int sz = 20;
int x0 = 50, y0 = 70;
Point org(x0, y0);
int j = 0, column = 1;
for(const TextProp& t: text)
{
PutTextFlags flags = t.ralign ? PUT_TEXT_ALIGN_RIGHT : PUT_TEXT_ALIGN_LEFT;
if(t.ralign)
{
if(j > 0)
break;
if(column == 1)
{
column = 2;
org.y = y0;
}
org.x = img.cols - x0;
}
else
{
org.x = column == 1 ? x0 : img.cols/2;
}
FontFace& face = t.italic ? italic : sans;
//Rect r = getTextSize(img.size(), t.str, org, face, sz, t.weight, flags);
org = putText(img, t.str, org, color, face,
sz, t.weight, flags, Range());
//rectangle(img, r, Scalar(80, 0, 128), 1, LINE_AA);
org.y += sz + 10;
}
Scalar color2(80, 0, 128);
org = Point(img.cols - 500, 150);
putText(img, "Пробуем\n ", org, color2, italic, 80, 300,
PUT_TEXT_ALIGN_LEFT, Range());
org.x -= 90;
org.y += 130;
// testing alternative way to set the weight;
// in putText we use weight=0
italic.setInstance({CV_FOURCC('w','g','h','t'), 800<<16});
putText(img, "OpenCV", org, color2, italic, 120, 0,
PUT_TEXT_ALIGN_LEFT, Range());
org.y += 140;
org.x += 60;
putText(img, "打印文字", org, color2, sans, 100, 400,
PUT_TEXT_ALIGN_LEFT, Range());
//ts = (double)getTickCount() - ts;
//printf("iter=%d. ts=%.2fms\n", iter, ts*1000./getTickFrequency());
}
#if 0
//imwrite(ts_data_path + "../highgui/drawing/text_test.png", img);
imshow("test", img);
waitKey();
#else
Mat refimg = imread(ts_data_path + "../highgui/drawing/text_test.png", IMREAD_UNCHANGED);
//imshow("ref", refimg);
//imshow("actual", img);
//absdiff(refimg, img, refimg);
//imshow("diff", refimg);
//waitKey();
EXPECT_EQ(refimg.size(), img.size());
EXPECT_LT(cv::norm(refimg, img, NORM_L1), 6500);
#endif
}
#endif
}} // namespace

@ -413,19 +413,6 @@ enum
//! Macro to construct the fourcc code of the codec. Same as CV_FOURCC()
#define CV_FOURCC_MACRO(c1, c2, c3, c4) (((c1) & 255) + (((c2) & 255) << 8) + (((c3) & 255) << 16) + (((c4) & 255) << 24))
/** @brief Constructs the fourcc code of the codec function
Simply call it with 4 chars fourcc code like `CV_FOURCC('I', 'Y', 'U', 'V')`
List of codes can be obtained at [Video Codecs by FOURCC](http://www.fourcc.org/codecs.php) page.
FFMPEG backend with MP4 container natively uses other values as fourcc code:
see [ObjectType](http://mp4ra.org/#/codecs).
*/
CV_INLINE int CV_FOURCC(char c1, char c2, char c3, char c4)
{
return CV_FOURCC_MACRO(c1, c2, c3, c4);
}
//! (Windows only) Open Codec Selection Dialog
#define CV_FOURCC_PROMPT -1
//! (Linux only) Use default codec for specified filename

@ -36,7 +36,7 @@ import glob, re, os, os.path, shutil, string, sys, argparse, traceback, multipro
from subprocess import check_call, check_output, CalledProcessError
from distutils.dir_util import copy_tree
IPHONEOS_DEPLOYMENT_TARGET='8.0' # default, can be changed via command line options or environment variable
IPHONEOS_DEPLOYMENT_TARGET='9.0' # default, can be changed via command line options or environment variable
def execute(cmd, cwd = None):
print("Executing: %s in %s" % (cmd, cwd), file=sys.stderr)
@ -426,8 +426,8 @@ if __name__ == "__main__":
parser.add_argument('--dynamic', default=False, action='store_true', help='build dynamic framework (default is "False" - builds static framework)')
parser.add_argument('--disable-bitcode', default=False, dest='bitcodedisabled', action='store_true', help='disable bitcode (enabled by default)')
parser.add_argument('--iphoneos_deployment_target', default=os.environ.get('IPHONEOS_DEPLOYMENT_TARGET', IPHONEOS_DEPLOYMENT_TARGET), help='specify IPHONEOS_DEPLOYMENT_TARGET')
parser.add_argument('--iphoneos_archs', default='armv7,armv7s,arm64', help='select iPhoneOS target ARCHS')
parser.add_argument('--iphonesimulator_archs', default='i386,x86_64', help='select iPhoneSimulator target ARCHS')
parser.add_argument('--iphoneos_archs', default='armv7s,arm64', help='select iPhoneOS target ARCHS')
parser.add_argument('--iphonesimulator_archs', default='x86_64', help='select iPhoneSimulator target ARCHS')
parser.add_argument('--enable_nonfree', default=False, dest='enablenonfree', action='store_true', help='enable non-free modules (disabled by default)')
parser.add_argument('--debug', default=False, dest='debug', action='store_true', help='Build "Debug" binaries (disabled by default)')
parser.add_argument('--debug_info', default=False, dest='debug_info', action='store_true', help='Build with debug information (useful for Release mode: BUILD_WITH_DEBUG_INFO=ON)')

@ -7,7 +7,7 @@ from __future__ import print_function
import glob, re, os, os.path, shutil, string, sys, argparse, traceback, multiprocessing
from subprocess import check_call, check_output, CalledProcessError
IPHONEOS_DEPLOYMENT_TARGET='8.0' # default, can be changed via command line options or environment variable
IPHONEOS_DEPLOYMENT_TARGET='9.0' # default, can be changed via command line options or environment variable
def execute(cmd, cwd = None):
print("Executing: %s in %s" % (cmd, cwd), file=sys.stderr)

Loading…
Cancel
Save