code_app/imgfmt/HGOfdImpl.cpp

759 lines
17 KiB
C++
Raw Normal View History

2022-05-03 10:25:52 +00:00
#include "HGOfdImpl.hpp"
#include "../base/HGInc.h"
#include "../base/HGUtility.h"
#include "../utility/HGString.h"
#define A4page_page_PhysicalBox_Width 210.000000
#define A4page_page_PhysicalBox_Height 297.000000
HGOfdReaderImpl::HGOfdReaderImpl()
{
m_zip = NULL;
}
HGOfdReaderImpl::~HGOfdReaderImpl()
{
}
HGResult HGOfdReaderImpl::Open(const HGChar* fileName)
{
if (NULL != m_zip)
{
return HGBASE_ERR_FAIL;
}
int error = 0;
m_zip = zip_open(StdStringToUtf8(fileName).c_str(), 0, &error);
if (NULL == m_zip)
{
return HGBASE_ERR_FAIL;
}
std::string content;
if (!ReadXml("Doc_0/Document.xml", content))
{
zip_close(m_zip);
m_zip = NULL;
return HGBASE_ERR_FAIL;
}
tinyxml2::XMLDocument xmlDoc;
if (tinyxml2::XML_SUCCESS == xmlDoc.Parse(content.c_str()))
{
tinyxml2::XMLElement* root = xmlDoc.RootElement();
if (NULL != root)
{
tinyxml2::XMLElement* pages = root->FirstChildElement("ofd:Pages");
if (NULL != pages)
{
tinyxml2::XMLElement* page = pages->FirstChildElement("ofd:Page");
if (NULL != page)
{
const char* attr = page->Attribute("BaseLoc");
if (NULL != attr)
m_contentNames.push_back(attr);
tinyxml2::XMLElement* p = page->NextSiblingElement("ofd:Page");
while (NULL != p)
{
const char* attr = p->Attribute("BaseLoc");
if (NULL != attr)
m_contentNames.push_back(attr);
p = p->NextSiblingElement("ofd:Page");
}
}
}
}
}
return HGBASE_ERR_OK;
}
HGResult HGOfdReaderImpl::Close()
{
if (NULL == m_zip)
{
return HGBASE_ERR_FAIL;
}
m_contentNames.clear();
zip_close(m_zip);
m_zip = NULL;
return HGBASE_ERR_OK;
}
HGResult HGOfdReaderImpl::GetPageCount(HGUInt* count)
{
if (NULL == m_zip)
{
return HGBASE_ERR_FAIL;
}
if (NULL == count)
{
return HGBASE_ERR_INVALIDARG;
}
*count = (HGUInt)m_contentNames.size();
return HGBASE_ERR_OK;
}
static bool GetRect(const char *text, double data[4])
{
bool ret = false;
if (NULL == text)
{
return ret;
}
char str[256];
strcpy(str, text);
int i = 0;
char* pStr = strtok(str, " ");
if (NULL != pStr)
{
data[i] = atof(pStr);
++i;
}
while (i < 4)
{
pStr = strtok(NULL, " ");
if (NULL == pStr)
break;
data[i] = atof(pStr);
++i;
}
return (4 == i);
}
HGResult HGOfdReaderImpl::GetPageInfo(HGUInt page, HGOfdPageInfo* info)
{
if (NULL == m_zip)
{
return HGBASE_ERR_FAIL;
}
if (page >= (HGUInt)m_contentNames.size() || NULL == info)
{
return HGBASE_ERR_INVALIDARG;
}
char name[128];
sprintf(name, "Doc_0/%s", m_contentNames[page].c_str());
std::string content;
if (!ReadXml(name, content))
{
return HGBASE_ERR_FAIL;
}
HGResult ret = HGBASE_ERR_FAIL;
tinyxml2::XMLDocument xmlDoc;
if (tinyxml2::XML_SUCCESS == xmlDoc.Parse(content.c_str()))
{
tinyxml2::XMLElement* root = xmlDoc.RootElement();
if (NULL != root)
{
tinyxml2::XMLElement* area = root->FirstChildElement("ofd:Area");
if (NULL != area)
{
tinyxml2::XMLElement* physicalBox = area->FirstChildElement("ofd:PhysicalBox");
if (NULL != physicalBox)
{
double data[4];
if (GetRect(physicalBox->GetText(), data))
{
info->width = (HGUInt)data[2];
info->height = (HGUInt)data[3];
ret = HGBASE_ERR_OK;
}
}
}
}
}
return ret;
}
HGResult HGOfdReaderImpl::LoadImage(HGUInt page, HGFloat xScale, HGFloat yScale,
HGUInt imgType, HGUInt imgOrigin, HGImage* image)
{
if (NULL == m_zip)
{
return HGBASE_ERR_FAIL;
}
if (page >= (HGUInt)m_contentNames.size() || NULL == image)
{
return HGBASE_ERR_INVALIDARG;
}
char name[128];
sprintf(name, "Doc_0/%s", m_contentNames[page].c_str());
std::string content;
if (!ReadXml(name, content))
{
return HGBASE_ERR_FAIL;
}
tinyxml2::XMLDocument xmlDoc;
std::string resId;
if (tinyxml2::XML_SUCCESS == xmlDoc.Parse(content.c_str()))
{
tinyxml2::XMLElement* root = xmlDoc.RootElement();
if (NULL != root)
{
tinyxml2::XMLElement* content = root->FirstChildElement("ofd:Content");
if (NULL != content)
{
tinyxml2::XMLElement* layer = content->FirstChildElement("ofd:Layer");
if (NULL != layer)
{
const char* attr = layer->Attribute("Type");
#if defined(HG_CMP_MSC)
if (NULL == attr || 0 != _stricmp("Background", attr))
#else
if (NULL == attr || 0 != strcasecmp("Background", attr))
#endif
{
tinyxml2::XMLElement* p = layer->NextSiblingElement("ofd:Layer");
while (NULL != p)
{
const char* attr = p->Attribute("Type");
#if defined(HG_CMP_MSC)
if (NULL != attr && 0 == _stricmp("Background", attr))
#else
if (NULL != attr && 0 == strcasecmp("Background", attr))
#endif
{
break;
}
p = p->NextSiblingElement("ofd:Layer");
}
layer = p;
}
if (NULL != layer)
{
tinyxml2::XMLElement* imgObject = layer->FirstChildElement("ofd:ImageObject");
if (NULL != imgObject)
{
resId = imgObject->Attribute("ResourceID");
}
}
}
}
}
}
if (resId.empty())
{
return HGBASE_ERR_FAIL;
}
if (!ReadXml("Doc_0/DocumentRes.xml", content))
{
return HGBASE_ERR_FAIL;
}
std::string imgName;
if (tinyxml2::XML_SUCCESS == xmlDoc.Parse(content.c_str()))
{
tinyxml2::XMLElement* root = xmlDoc.RootElement();
if (NULL != root)
{
tinyxml2::XMLElement* multiMedias = root->FirstChildElement("ofd:MultiMedias");
if (NULL != multiMedias)
{
tinyxml2::XMLElement* multiMedia = multiMedias->FirstChildElement("ofd:MultiMedia");
if (NULL != multiMedia)
{
const char* attr = multiMedia->Attribute("ID");
#if defined(HG_CMP_MSC)
if (NULL == attr || 0 != _stricmp(resId.c_str(), attr))
#else
if (NULL == attr || 0 != strcasecmp(resId.c_str(), attr))
#endif
{
tinyxml2::XMLElement* p = multiMedia->NextSiblingElement("ofd:MultiMedia");
while (NULL != p)
{
const char* attr = p->Attribute("ID");
#if defined(HG_CMP_MSC)
if (NULL != attr && 0 == _stricmp(resId.c_str(), attr))
#else
if (NULL != attr && 0 == strcasecmp(resId.c_str(), attr))
#endif
{
break;
}
p = p->NextSiblingElement("ofd:MultiMedia");
}
multiMedia = p;
}
if (NULL != multiMedia)
{
tinyxml2::XMLElement* mediaFile = multiMedia->FirstChildElement("ofd:MediaFile");
if (NULL != mediaFile)
{
imgName = mediaFile->GetText();
}
}
}
}
}
}
if (imgName.empty())
{
return HGBASE_ERR_FAIL;
}
char img_name[128];
sprintf(img_name, "Doc_0/Res/%s", imgName.c_str());
if (!ReadJpeg(img_name, xScale, yScale, imgType, imgOrigin, image))
{
return HGBASE_ERR_FAIL;
}
return HGBASE_ERR_OK;
}
bool HGOfdReaderImpl::ReadXml(const char* name, std::string& content)
{
struct zip_stat st;
zip_stat_init(&st);
zip_stat(m_zip, name, ZIP_FL_NOCASE, &st);
zip_int64_t size = st.size;
if (0 == size)
{
return false;
}
zip_file* file = zip_fopen(m_zip, name, ZIP_FL_NOCASE);
if (NULL == file)
{
return false;
}
char* s = (char*)malloc((size_t)size + 1);
if (NULL == s)
{
zip_fclose(file);
return false;
}
zip_int64_t did_read = zip_fread(file, s, size);
if (did_read != size)
{
free(s);
zip_fclose(file);
return false;
}
s[size] = 0;
content = s;
free(s);
zip_fclose(file);
return true;
}
bool HGOfdReaderImpl::ReadJpeg(const char* name, HGFloat xScale, HGFloat yScale, HGUInt imgType, HGUInt imgOrigin, HGImage* image)
{
struct zip_stat st;
zip_stat_init(&st);
zip_stat(m_zip, name, ZIP_FL_NOCASE, &st);
zip_int64_t size = st.size;
if (0 == size)
{
return false;
}
zip_file* file = zip_fopen(m_zip, name, ZIP_FL_NOCASE);
if (NULL == file)
{
return false;
}
unsigned char* content = (unsigned char*)malloc((size_t)size);
if (NULL == content)
{
zip_fclose(file);
return false;
}
zip_int64_t did_read = zip_fread(file, content, size);
if (did_read != size)
{
free(content);
zip_fclose(file);
return false;
}
HGBuffer buffer = NULL;
HGBase_CreateBufferWithData(content, (size_t)size, &buffer);
HGResult ret = HGImgFmt_LoadJpegImageFromBuffer(buffer, NULL, imgType, imgOrigin, image);
HGBase_DestroyBuffer(buffer);
free(content);
zip_fclose(file);
return (HGBASE_ERR_OK == ret);
}
HGOfdImageWriterImpl::HGOfdImageWriterImpl()
{
m_zip = NULL;
m_curImgIndex = 0;
}
HGOfdImageWriterImpl::~HGOfdImageWriterImpl()
{
}
HGResult HGOfdImageWriterImpl::Open(const HGChar* fileName)
{
if (NULL != m_zip)
{
return HGBASE_ERR_FAIL;
}
int error = 0;
m_zip = zip_open(StdStringToUtf8(fileName).c_str(), ZIP_CREATE | ZIP_TRUNCATE, &error);
if (NULL == m_zip)
{
return HGBASE_ERR_FAIL;
}
zip_add_dir(m_zip, "Doc_0");
zip_add_dir(m_zip, "Doc_0/Pages");
zip_add_dir(m_zip, "Doc_0/Res");
if (!AddOfdXml() || !AddPublicResXml())
{
zip_close(m_zip);
m_zip = NULL;
return HGBASE_ERR_FAIL;
}
return HGBASE_ERR_OK;
}
HGResult HGOfdImageWriterImpl::Close()
{
if (NULL == m_zip)
{
return HGBASE_ERR_FAIL;
}
AddDocXml();
AddDocResXml();
zip_close(m_zip);
m_zip = NULL;
// 清理临时文件
std::list<std::string>::const_iterator iter;
for (iter = m_tmpFiles.begin(); iter != m_tmpFiles.end(); ++iter)
{
HGBase_DeleteFile(iter->c_str());
}
m_tmpFiles.clear();
return HGBASE_ERR_OK;
}
HGResult HGOfdImageWriterImpl::SaveJpegImage(HGImage image, const HGJpegSaveInfo* info, HGUInt quality)
{
HGChar name[128];
sprintf(name, "Doc_0/Res/image_%u.jpg", m_curImgIndex);
if (!AddJpegImageFile(image, info, quality, name))
{
return HGBASE_ERR_FAIL;
}
HGImageInfo imgInfo;
HGBase_GetImageInfo(image, &imgInfo);
HGFloat physicalWidth = 25.4f * (HGFloat)imgInfo.width / 96.0f;
HGFloat physicalHeight = 25.4f * (HGFloat)imgInfo.height / 96.0f;
AddContentXmlFile(m_curImgIndex, physicalWidth, physicalHeight);
++m_curImgIndex;
return HGBASE_ERR_OK;
}
bool HGOfdImageWriterImpl::AddOfdXml()
{
tinyxml2::XMLDocument xmlDoc;
HGChar uuid[128];
HGBase_GetUuid(uuid, 128);
time_t tm = time(NULL);
struct tm *local_tm = localtime(&tm);
char local_tm_str[256];
strftime(local_tm_str, 256, "%c", local_tm);
tinyxml2::XMLElement *root = xmlDoc.NewElement("ofd:OFD");
root->SetAttribute("xmlns:ofd", "http://www.ofdspec.org/2016");
root->SetAttribute("DocType", "OFD");
root->SetAttribute("Version", "1.0");
xmlDoc.InsertEndChild(root);
tinyxml2::XMLElement* docBody = xmlDoc.NewElement("ofd:DocBody");
root->InsertEndChild(docBody);
tinyxml2::XMLElement* docRoot = xmlDoc.NewElement("ofd:DocRoot");
docRoot->SetText("Doc_0/Document.xml");
docBody->InsertEndChild(docRoot);
tinyxml2::XMLElement* docInfo = xmlDoc.NewElement("ofd:DocInfo");
docBody->InsertEndChild(docInfo);
tinyxml2::XMLElement* docId = xmlDoc.NewElement("ofd:DocID");
docId->SetText(uuid);
docInfo->InsertEndChild(docId);
tinyxml2::XMLElement* creationDate = xmlDoc.NewElement("ofd:CreationDate");
creationDate->SetText(local_tm_str);
docInfo->InsertEndChild(creationDate);
tinyxml2::XMLElement* modDate = xmlDoc.NewElement("ofd:ModDate");
modDate->SetText(local_tm_str);
docInfo->InsertEndChild(modDate);
tinyxml2::XMLElement* creator = xmlDoc.NewElement("ofd:Creator");
creator->SetText("HuaGo");
docInfo->InsertEndChild(creator);
tinyxml2::XMLElement* createVersion = xmlDoc.NewElement("ofd:CreatorVersion");
createVersion->SetText("1.0.0");
docInfo->InsertEndChild(createVersion);
return AddXmlFile(xmlDoc, "OFD.xml");
}
bool HGOfdImageWriterImpl::AddDocXml()
{
tinyxml2::XMLDocument xmlDoc;
tinyxml2::XMLElement* root = xmlDoc.NewElement("ofd:Document");
root->SetAttribute("xmlns:ofd", "http://www.ofdspec.org/2016");
xmlDoc.InsertEndChild(root);
tinyxml2::XMLElement* commonData = xmlDoc.NewElement("ofd:CommonData");
root->InsertEndChild(commonData);
tinyxml2::XMLElement* maxUnitID = xmlDoc.NewElement("ofd:MaxUnitID");
HGChar maxId[24];
sprintf(maxId, "%u", m_curImgIndex * 10 + 2);
maxUnitID->SetText(maxId);
commonData->InsertEndChild(maxUnitID);
tinyxml2::XMLElement* pageArea = xmlDoc.NewElement("ofd:PageArea");
commonData->InsertEndChild(pageArea);
tinyxml2::XMLElement* publicRes = xmlDoc.NewElement("ofd:PublicRes");
publicRes->SetText("PublicRes.xml");
commonData->InsertEndChild(publicRes);
tinyxml2::XMLElement* documentRes = xmlDoc.NewElement("ofd:DocumentRes");
documentRes->SetText("DocumentRes.xml");
commonData->InsertEndChild(documentRes);
tinyxml2::XMLElement* physicalBox = xmlDoc.NewElement("ofd:PhysicalBox");
char physicalBoxText[512];
sprintf(physicalBoxText, "0.000000 0.000000 %f %f", A4page_page_PhysicalBox_Width,
A4page_page_PhysicalBox_Height);
physicalBox->SetText(physicalBoxText);
pageArea->InsertEndChild(physicalBox);
tinyxml2::XMLElement* pages = xmlDoc.NewElement("ofd:Pages");
root->InsertEndChild(pages);
for (HGUInt i = 0; i < m_curImgIndex; ++i)
{
tinyxml2::XMLElement* page = xmlDoc.NewElement("ofd:Page");
HGChar id[24];
sprintf(id, "%u", i * 10 + 1);
page->SetAttribute("ID", id);
HGChar loc[128];
sprintf(loc, "Pages/Page_%u/Content.xml", i);
page->SetAttribute("BaseLoc", loc);
pages->InsertEndChild(page);
}
return AddXmlFile(xmlDoc, "Doc_0/Document.xml");
}
bool HGOfdImageWriterImpl::AddDocResXml()
{
tinyxml2::XMLDocument xmlDoc;
tinyxml2::XMLElement* root = xmlDoc.NewElement("ofd:Res");
root->SetAttribute("xmlns:ofd", "http://www.ofdspec.org/2016");
root->SetAttribute("BaseLoc", "Res");
xmlDoc.InsertEndChild(root);
tinyxml2::XMLElement* multiMedias = xmlDoc.NewElement("ofd:MultiMedias");
root->InsertEndChild(multiMedias);
for (HGUInt i = 0; i < m_curImgIndex; ++i)
{
tinyxml2::XMLElement* multiMedia = xmlDoc.NewElement("ofd:MultiMedia");
multiMedia->SetAttribute("Type", "Image");
HGChar id[24];
sprintf(id, "%u", i * 10 + 2);
multiMedia->SetAttribute("ID", id);
multiMedias->InsertEndChild(multiMedia);
tinyxml2::XMLElement* mediaFile = xmlDoc.NewElement("ofd:MediaFile");
HGChar loc[128];
sprintf(loc, "image_%u.jpg", i);
mediaFile->SetText(loc);
multiMedia->InsertEndChild(mediaFile);
}
return AddXmlFile(xmlDoc, "Doc_0/DocumentRes.xml");
}
bool HGOfdImageWriterImpl::AddPublicResXml()
{
tinyxml2::XMLDocument xmlDoc;
tinyxml2::XMLElement* root = xmlDoc.NewElement("ofd:Res");
root->SetAttribute("xmlns:ofd", "http://www.ofdspec.org/2016");
root->SetAttribute("BaseLoc", "Res");
xmlDoc.InsertEndChild(root);
tinyxml2::XMLElement* fonts = xmlDoc.NewElement("ofd:Fonts");
root->InsertEndChild(fonts);
return AddXmlFile(xmlDoc, "Doc_0/PublicRes.xml");
}
bool HGOfdImageWriterImpl::AddXmlFile(tinyxml2::XMLDocument& xmlDoc, const HGChar* name)
{
HGChar tmpName[256];
HGBase_GetTmpFileName(tmpName, 256);
if (tinyxml2::XML_SUCCESS != xmlDoc.SaveFile(tmpName))
{
return false;
}
zip_source_t* s = zip_source_file(m_zip, tmpName, 0, 0);
if (NULL == s)
{
HGBase_DeleteFile(tmpName);
return false;
}
zip_int64_t ret = zip_file_add(m_zip, name, s, ZIP_FL_ENC_UTF_8 | ZIP_FL_OVERWRITE);
if (ret < 0)
{
zip_source_free(s);
HGBase_DeleteFile(tmpName);
return false;
}
m_tmpFiles.push_back(tmpName);
return true;
}
bool HGOfdImageWriterImpl::AddJpegImageFile(HGImage image, const HGJpegSaveInfo* info, HGUInt quality, const HGChar* name)
{
HGChar tmpName[256];
HGBase_GetTmpFileName(tmpName, 256);
if (HGBASE_ERR_OK != HGImgFmt_SaveJpegImage(image, info, quality, tmpName))
{
return false;
}
zip_source_t* s = zip_source_file(m_zip, tmpName, 0, 0);
if (NULL == s)
{
HGBase_DeleteFile(tmpName);
return false;
}
zip_int64_t ret = zip_file_add(m_zip, name, s, ZIP_FL_OVERWRITE);
if (ret < 0)
{
zip_source_free(s);
HGBase_DeleteFile(tmpName);
return false;
}
m_tmpFiles.push_back(tmpName);
return true;
}
bool HGOfdImageWriterImpl::AddContentXmlFile(HGUInt index, HGFloat physicalWidth, HGFloat physicalHeight)
{
HGChar dir[128];
sprintf(dir, "Doc_0/Pages/Page_%u", index);
zip_add_dir(m_zip, dir);
tinyxml2::XMLDocument xmlDoc;
tinyxml2::XMLElement* root = xmlDoc.NewElement("ofd:Page");
root->SetAttribute("xmlns:ofd", "http://www.ofdspec.org/2016");
xmlDoc.InsertEndChild(root);
tinyxml2::XMLElement* area = xmlDoc.NewElement("ofd:Area");
root->InsertEndChild(area);
tinyxml2::XMLElement* physicalBox = xmlDoc.NewElement("ofd:PhysicalBox");
char physicalBoxText[512];
sprintf(physicalBoxText, "0.000000 0.000000 %f %f", physicalWidth, physicalHeight);
physicalBox->SetText(physicalBoxText);
area->InsertEndChild(physicalBox);
tinyxml2::XMLElement* content = xmlDoc.NewElement("ofd:Content");
root->InsertEndChild(content);
tinyxml2::XMLElement* layer = xmlDoc.NewElement("ofd:Layer");
HGChar layerId[24];
sprintf(layerId, "%u", index * 10 + 3);
layer->SetAttribute("ID", layerId);
layer->SetAttribute("Type", "Background");
content->InsertEndChild(layer);
tinyxml2::XMLElement* imgObject = xmlDoc.NewElement("ofd:ImageObject");
HGChar imgObjectId[24];
sprintf(imgObjectId, "%u", index * 10 + 4);
imgObject->SetAttribute("ID", imgObjectId);
char boundaryText[512];
sprintf(boundaryText, "0.000000 0.000000 %f %f", physicalWidth, physicalHeight);
imgObject->SetAttribute("Boundary", boundaryText);
HGChar imgObjectResId[24];
sprintf(imgObjectResId, "%u", index * 10 + 2);
imgObject->SetAttribute("ResourceID", imgObjectResId);
char ctmText[512];
sprintf(ctmText, "%f 0 0 %f 0 0", physicalWidth, physicalHeight);
imgObject->SetAttribute("CTM", ctmText);
layer->InsertEndChild(imgObject);
HGChar name[128];
sprintf(name, "%s/Content.xml", dir);
return AddXmlFile(xmlDoc, name);
}