系列文章目录
文章目录
前言
在 OpenSceneGraph 3.6.5 和 osgEarth 3.2 中,文本渲染统一使用 UTF‑8 编码。如果传入的字符串不是 UTF‑8(例如 Windows 下的 GBK/ANSI),就会出现乱码。要显示中文,必须保证传入的 std::string 是 UTF‑8,并且指定一个支持中文的字体文件(如 simsun.ttc、msyh.ttc)。否则会出现显示中文乱码的情况

一、osgEarth中文乱码的原因是什么?
在 osgEarth 三维地图中出现中文乱码,核心原因是文本编码转换错误或显示端编码不匹配,具体可分为以下几点:
1.源文件编码与 Qt 字符串处理不匹配若项目源文件(如.cpp)使用 GBK 编码(非 UTF-8),在 Qt 中直接定义中文字符串(如QString text = "中文标签")时,Qt 会默认将其按源文件编码(GBK)解析为 Unicode 字符。但由于编码解析错误,QString内部可能存储的是乱码的 Unicode 数据,后续转换为 UTF-8 时自然会出现乱码。
2.osgEarth 文本显示编码未明确指定osgEarth 的TextSymbol默认编码可能不支持 UTF-8,若未显式设置encoding()为ENCODING_UTF8,即使传入的字符串是正确的 UTF-8 格式,osgEarth 也可能用其他编码(如 ASCII)解析,导致中文无法识别。
3.缺少中文字体支持若 osgEarth 使用的字体不包含中文字符集(如默认的英文字体),即使编码正确,中文也会显示为方块或空白(本质是 "无法渲染" 而非 "乱码",但常被归为同类问题)。
二、解决方法
解决方法总结
针对上述原因,代码中采用了以下解决方案,可彻底解决中文乱码问题:
修复源文件编码导致的字符串乱码若源文件为 GBK 编码,需先将错误解析的QString还原为正确的 Unicode 字符串,再转换为 UTF-8:
用QTextCodec::codecForName("GBK")获取 GBK 编码器;
通过fromUnicode(text)提取原始 GBK 字节(还原源文件编码的字节流);
用toUnicode(gbkBytes)重新解析为正确的 Unicode 字符串;
最终通过toStdString()转换为 UTF-8 格式的std::string,供 osgEarth 使用。
显式指定 osgEarth 文本编码为 UTF-8在TextSymbol中明确设置编码,确保 osgEarth 用 UTF-8 解析文本:
cpp
运行
osgEarth::TextSymbol* ts = style.getOrCreateSymbolosgEarth::TextSymbol();
ts->encoding() = osgEarth::TextSymbol::ENCODING_UTF8; // 强制UTF-8编码
确保使用支持中文的字体(补充建议)代码中注释了字体路径设置,实际使用时需指定包含中文字符的字体(如 "微软雅黑""黑体" 等):
cpp
运行
QString fontPath = QCoreApplication::applicationDirPath() + "/fonts/simhei.ttf"; // 黑体字体
ts->font() = fontPath.toStdString(); // 关联字体文件
通过以上步骤,可确保中文从 "字符串定义" 到 "osgEarth 渲染" 的全流程编码一致,彻底解决乱码问题。
cpp
osg::ref_ptr<osgEarth::PlaceNode> AmainWidget::createLabel(const QString& text, double lon, double lat)
{
const osgEarth::SpatialReference* wgs84 = osgEarth::SpatialReference::get("wgs84");
osgEarth::GeoPoint geoPoint(wgs84, lon, lat, 0.0, osgEarth::ALTMODE_RELATIVE);
// 调试输出(保留,用于验证编码)
qDebug() << QString::fromLocal8Bit("[QString原始内容]:") << text;
qDebug() << QString::fromLocal8Bit("[QString长度]:") << text.length();
QByteArray utf8Bytes = text.toUtf8();
qDebug() << QString::fromLocal8Bit("[UTF-8字节数]:") << utf8Bytes.size();
qDebug() << QString::fromLocal8Bit("[UTF-8十六进制]:") << utf8Bytes.toHex();
// 修正:正确的编码转换逻辑(解决QByteArray::toUtf8()错误)
std::string utf8Text;
// 情况1:若原始QString因源文件GBK编码导致内部乱码(常见于非UTF-8源文件)
QTextCodec* gbkCodec = QTextCodec::codecForName("GBK");
if (gbkCodec) {
// 步骤1:将GBK编码的字节(错误解析的QString)还原为正确的Unicode QString
// (原理:假设text内部是GBK字节误解析为Unicode,先提取GBK字节,再重新解析为Unicode)
QByteArray gbkBytes = gbkCodec->fromUnicode(text); // 提取GBK字节
QString correctText = gbkCodec->toUnicode(gbkBytes); // 用GBK重新解析为正确的QString
// 步骤2:将正确的QString转为UTF-8的std::string
utf8Text = correctText.toStdString(); // 用toUtf8()而非toLocal8Bit()
}
else {
// 情况2:正常情况,直接转换
utf8Text = text.toUtf8().toStdString();
}
// 验证转换结果
qDebug() << QString::fromLocal8Bit("[转换后std::string]:") << QString::fromUtf8(utf8Text.c_str());
// 创建 PlaceNode 及样式设置(保持不变)
osg::ref_ptr<osgEarth::PlaceNode> placeNode = new osgEarth::PlaceNode(geoPoint, utf8Text);
osgEarth::Style style;
osgEarth::TextSymbol* ts = style.getOrCreateSymbol<osgEarth::TextSymbol>();
ts->size() = osgEarth::NumericExpression("18");
ts->fill()->color() = osgEarth::Color::Yellow;
ts->halo()->color() = osgEarth::Color::Black;
ts->alignment() = osgEarth::TextSymbol::ALIGN_CENTER_CENTER;
QString fontPath = QCoreApplication::applicationDirPath() + "/fonts/simhei.ttf";
ts->font() = fontPath.toStdString(); // 确保字体文件存在
ts->encoding() = osgEarth::TextSymbol::ENCODING_UTF8; // 明确UTF-8编码
placeNode->setStyle(style);
return placeNode;
}
三、结果
