diff --git a/app/HGProductionTool/HGImgView.cpp b/app/HGProductionTool/HGImgView.cpp new file mode 100644 index 0000000..b6f457e --- /dev/null +++ b/app/HGProductionTool/HGImgView.cpp @@ -0,0 +1,2473 @@ +#include "HGImgView.h" +#include +#include +#include +#include +#include +#include +#include "base/HGInc.h" +#include "imgfmt/HGImgFmt.h" +#include "HGUIGlobal.h" +#include + +HGImgView::HGImgView(QWidget* parent) + : QWidget(parent) +{ + m_scrollSize = 10; + m_minScrollSliderSize = 8; + for (int i = 0; i < 3; ++i) + { + m_hScrollLeftImage[i] = nullptr; + m_hScrollRightImage[i] = nullptr; + m_vScrollTopImage[i] = nullptr; + m_vScrollBottomImage[i] = nullptr; + m_hScrollSliderImage[i] = nullptr; + m_vScrollSliderImage[i] = nullptr; + } + m_hScrollImage = nullptr; + m_vScrollImage = nullptr; + m_nullScrollImage = nullptr; + + m_enableScroll = false; + m_mouseOn = false; + m_hScroll = false; + m_vScroll = false; + m_image = nullptr; + m_qImage = nullptr; + m_showImage = false; + memset(&m_showRect, 0, sizeof(HGRectF)); + m_mouseMoveStatus = MouseStatus_Null; + m_mousePressStatus = MouseStatus_Null; + m_mousePressBeginX = -1; + m_mousePressBeginY = -1; + m_showColorInfo = false; + m_operate = 0; + m_beginX = -1; + m_beginY = -1; + m_draging = false; + + setFocusPolicy(Qt::ClickFocus); + setMouseTracking(true); + setAcceptDrops(true); +} + +HGImgView::~HGImgView() +{ + clearImage(); + + delete m_hScrollImage; + m_hScrollImage = nullptr; + delete m_vScrollImage; + m_vScrollImage = nullptr; + delete m_nullScrollImage; + m_nullScrollImage = nullptr; + for (int i = 0; i < 3; ++i) + { + delete m_hScrollLeftImage[i]; + m_hScrollLeftImage[i] = nullptr; + delete m_hScrollRightImage[i]; + m_hScrollRightImage[i] = nullptr; + delete m_vScrollTopImage[i]; + m_vScrollTopImage[i] = nullptr; + delete m_vScrollBottomImage[i]; + m_vScrollBottomImage[i] = nullptr; + delete m_hScrollSliderImage[i]; + m_hScrollSliderImage[i] = nullptr; + delete m_vScrollSliderImage[i]; + m_vScrollSliderImage[i] = nullptr; + } + + qDebug("~HGImgView"); +} + +HGResult HGImgView::setScrollSize(int size) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (size < 10 || size > 20) + { + return HGBASE_ERR_INVALIDARG; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + m_scrollSize = size; + return HGBASE_ERR_OK; +} + +HGResult HGImgView::setMinScrollSliderSize(int size) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (size < 8 || size > 64) + { + return HGBASE_ERR_INVALIDARG; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + m_minScrollSliderSize = size; + return HGBASE_ERR_OK; +} + +HGResult HGImgView::setHScrollLeftImage(const QImage *normalImage, const QImage *hotImage, const QImage *pushImage) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr == normalImage) + { + delete m_hScrollLeftImage[0]; + m_hScrollLeftImage[0] = nullptr; + } + else + { + QImage *img = new QImage(*normalImage); + if (!img->isNull()) + { + if (nullptr != m_hScrollLeftImage[0]) + delete m_hScrollLeftImage[0]; + m_hScrollLeftImage[0] = img; + } + else + { + delete img; + } + } + + if (nullptr == hotImage) + { + delete m_hScrollLeftImage[1]; + m_hScrollLeftImage[1] = nullptr; + } + else + { + QImage *img = new QImage(*hotImage); + if (!img->isNull()) + { + if (nullptr != m_hScrollLeftImage[1]) + delete m_hScrollLeftImage[1]; + m_hScrollLeftImage[1] = img; + } + else + { + delete img; + } + } + + if (nullptr == pushImage) + { + delete m_hScrollLeftImage[2]; + m_hScrollLeftImage[2] = nullptr; + } + else + { + QImage *img = new QImage(*pushImage); + if (!img->isNull()) + { + if (nullptr != m_hScrollLeftImage[2]) + delete m_hScrollLeftImage[2]; + m_hScrollLeftImage[2] = img; + } + else + { + delete img; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::setHScrollRightImage(const QImage *normalImage, const QImage *hotImage, const QImage *pushImage) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr == normalImage) + { + delete m_hScrollRightImage[0]; + m_hScrollRightImage[0] = nullptr; + } + else + { + QImage *img = new QImage(*normalImage); + if (!img->isNull()) + { + if (nullptr != m_hScrollRightImage[0]) + delete m_hScrollRightImage[0]; + m_hScrollRightImage[0] = img; + } + else + { + delete img; + } + } + + if (nullptr == hotImage) + { + delete m_hScrollRightImage[1]; + m_hScrollRightImage[1] = nullptr; + } + else + { + QImage *img = new QImage(*hotImage); + if (!img->isNull()) + { + if (nullptr != m_hScrollRightImage[1]) + delete m_hScrollRightImage[1]; + m_hScrollRightImage[1] = img; + } + else + { + delete img; + } + } + + if (nullptr == pushImage) + { + delete m_hScrollRightImage[2]; + m_hScrollRightImage[2] = nullptr; + } + else + { + QImage *img = new QImage(*pushImage); + if (!img->isNull()) + { + if (nullptr != m_hScrollRightImage[2]) + delete m_hScrollRightImage[2]; + m_hScrollRightImage[2] = img; + } + else + { + delete img; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::setVScrollTopImage(const QImage *normalImage, const QImage *hotImage, const QImage *pushImage) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr == normalImage) + { + delete m_vScrollTopImage[0]; + m_vScrollTopImage[0] = nullptr; + } + else + { + QImage *img = new QImage(*normalImage); + if (!img->isNull()) + { + if (nullptr != m_vScrollTopImage[0]) + delete m_vScrollTopImage[0]; + m_vScrollTopImage[0] = img; + } + else + { + delete img; + } + } + + if (nullptr == hotImage) + { + delete m_vScrollTopImage[1]; + m_vScrollTopImage[1] = nullptr; + } + else + { + QImage *img = new QImage(*hotImage); + if (!img->isNull()) + { + if (nullptr != m_vScrollTopImage[1]) + delete m_vScrollTopImage[1]; + m_vScrollTopImage[1] = img; + } + else + { + delete img; + } + } + + if (nullptr == pushImage) + { + delete m_vScrollTopImage[2]; + m_vScrollTopImage[2] = nullptr; + } + else + { + QImage *img = new QImage(*pushImage); + if (!img->isNull()) + { + if (nullptr != m_vScrollTopImage[2]) + delete m_vScrollTopImage[2]; + m_vScrollTopImage[2] = img; + } + else + { + delete img; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::setVScrollBottomImage(const QImage *normalImage, const QImage *hotImage, const QImage *pushImage) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr == normalImage) + { + delete m_vScrollBottomImage[0]; + m_vScrollBottomImage[0] = nullptr; + } + else + { + QImage *img = new QImage(*normalImage); + if (!img->isNull()) + { + if (nullptr != m_vScrollBottomImage[0]) + delete m_vScrollBottomImage[0]; + m_vScrollBottomImage[0] = img; + } + else + { + delete img; + } + } + + if (nullptr == hotImage) + { + delete m_vScrollBottomImage[1]; + m_vScrollBottomImage[1] = nullptr; + } + else + { + QImage *img = new QImage(*hotImage); + if (!img->isNull()) + { + if (nullptr != m_vScrollBottomImage[1]) + delete m_vScrollBottomImage[1]; + m_vScrollBottomImage[1] = img; + } + else + { + delete img; + } + } + + if (nullptr == pushImage) + { + delete m_vScrollBottomImage[2]; + m_vScrollBottomImage[2] = nullptr; + } + else + { + QImage *img = new QImage(*pushImage); + if (!img->isNull()) + { + if (nullptr != m_vScrollBottomImage[2]) + delete m_vScrollBottomImage[2]; + m_vScrollBottomImage[2] = img; + } + else + { + delete img; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::setHScrollImage(const QImage *image, const HGRect *stretch) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr == image) + { + delete m_hScrollImage; + m_hScrollImage = nullptr; + } + else + { + QImage *img = new QImage(*image); + if (!img->isNull()) + { + if (nullptr != m_hScrollImage) + delete m_hScrollImage; + m_hScrollImage = img; + + if (nullptr == stretch || stretch->left < 0 || stretch->top < 0 + || stretch->right > m_hScrollImage->width() || stretch->bottom > m_hScrollImage->height() + || stretch->left >= stretch->right || stretch->top >= stretch->bottom) + { + m_hScrollImageStretch.setX(0); + m_hScrollImageStretch.setY(0); + m_hScrollImageStretch.setWidth(m_hScrollImage->width()); + m_hScrollImageStretch.setHeight(m_hScrollImage->height()); + } + else + { + m_hScrollImageStretch.setX(stretch->left); + m_hScrollImageStretch.setY(stretch->top); + m_hScrollImageStretch.setWidth(stretch->right - stretch->left); + m_hScrollImageStretch.setHeight(stretch->bottom - stretch->top); + } + } + else + { + delete img; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::setHScrollSliderImage(const QImage *normalImage, const HGRect *normalStretch, const QImage *hotImage, const HGRect *hotStretch, + const QImage *pushImage, const HGRect *pushStretch) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr == normalImage) + { + delete m_hScrollSliderImage[0]; + m_hScrollSliderImage[0] = nullptr; + } + else + { + QImage *img = new QImage(*normalImage); + if (!img->isNull()) + { + if (nullptr != m_hScrollSliderImage[0]) + delete m_hScrollSliderImage[0]; + m_hScrollSliderImage[0] = img; + + if (nullptr == normalStretch || normalStretch->left < 0 || normalStretch->top < 0 + || normalStretch->right > m_hScrollSliderImage[0]->width() || normalStretch->bottom > m_hScrollSliderImage[0]->height() + || normalStretch->left >= normalStretch->right || normalStretch->top >= normalStretch->bottom) + { + m_hScrollSliderImageStretch[0].setX(0); + m_hScrollSliderImageStretch[0].setY(0); + m_hScrollSliderImageStretch[0].setWidth(m_hScrollSliderImage[0]->width()); + m_hScrollSliderImageStretch[0].setHeight(m_hScrollSliderImage[0]->height()); + } + else + { + m_hScrollSliderImageStretch[0].setX(normalStretch->left); + m_hScrollSliderImageStretch[0].setY(normalStretch->top); + m_hScrollSliderImageStretch[0].setWidth(normalStretch->right - normalStretch->left); + m_hScrollSliderImageStretch[0].setHeight(normalStretch->bottom - normalStretch->top); + } + } + else + { + delete img; + } + } + + if (nullptr == hotImage) + { + delete m_hScrollSliderImage[1]; + m_hScrollSliderImage[1] = nullptr; + } + else + { + QImage *img = new QImage(*hotImage); + if (!img->isNull()) + { + if (nullptr != m_hScrollSliderImage[1]) + delete m_hScrollSliderImage[1]; + m_hScrollSliderImage[1] = img; + + if (nullptr == hotStretch || hotStretch->left < 0 || hotStretch->top < 0 + || hotStretch->right > m_hScrollSliderImage[1]->width() || hotStretch->bottom > m_hScrollSliderImage[1]->height() + || hotStretch->left >= hotStretch->right || hotStretch->top >= hotStretch->bottom) + { + m_hScrollSliderImageStretch[1].setX(0); + m_hScrollSliderImageStretch[1].setY(0); + m_hScrollSliderImageStretch[1].setWidth(m_hScrollSliderImage[1]->width()); + m_hScrollSliderImageStretch[1].setHeight(m_hScrollSliderImage[1]->height()); + } + else + { + m_hScrollSliderImageStretch[1].setX(hotStretch->left); + m_hScrollSliderImageStretch[1].setY(hotStretch->top); + m_hScrollSliderImageStretch[1].setWidth(hotStretch->right - hotStretch->left); + m_hScrollSliderImageStretch[1].setHeight(hotStretch->bottom - hotStretch->top); + } + } + else + { + delete img; + } + } + + if (nullptr == pushImage) + { + delete m_hScrollSliderImage[2]; + m_hScrollSliderImage[2] = nullptr; + } + else + { + QImage *img = new QImage(*pushImage); + if (!img->isNull()) + { + if (nullptr != m_hScrollSliderImage[2]) + delete m_hScrollSliderImage[2]; + m_hScrollSliderImage[2] = img; + + if (nullptr == pushStretch || pushStretch->left < 0 || pushStretch->top < 0 + || pushStretch->right > m_hScrollSliderImage[2]->width() || pushStretch->bottom > m_hScrollSliderImage[2]->height() + || pushStretch->left >= pushStretch->right || pushStretch->top >= hotStretch->bottom) + { + m_hScrollSliderImageStretch[2].setX(0); + m_hScrollSliderImageStretch[2].setY(0); + m_hScrollSliderImageStretch[2].setWidth(m_hScrollSliderImage[2]->width()); + m_hScrollSliderImageStretch[2].setHeight(m_hScrollSliderImage[2]->height()); + } + else + { + m_hScrollSliderImageStretch[2].setX(pushStretch->left); + m_hScrollSliderImageStretch[2].setY(pushStretch->top); + m_hScrollSliderImageStretch[2].setWidth(pushStretch->right - pushStretch->left); + m_hScrollSliderImageStretch[2].setHeight(pushStretch->bottom - pushStretch->top); + } + } + else + { + delete img; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::setVScrollImage(const QImage *image, const HGRect *stretch) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr == image) + { + delete m_vScrollImage; + m_vScrollImage = nullptr; + } + else + { + QImage *img = new QImage(*image); + if (!img->isNull()) + { + if (nullptr != m_vScrollImage) + delete m_vScrollImage; + m_vScrollImage = img; + + if (nullptr == stretch || stretch->left < 0 || stretch->top < 0 + || stretch->right > m_vScrollImage->width() || stretch->bottom > m_vScrollImage->height() + || stretch->left >= stretch->right || stretch->top >= stretch->bottom) + { + m_vScrollImageStretch.setX(0); + m_vScrollImageStretch.setY(0); + m_vScrollImageStretch.setWidth(m_vScrollImage->width()); + m_vScrollImageStretch.setHeight(m_vScrollImage->height()); + } + else + { + m_vScrollImageStretch.setX(stretch->left); + m_vScrollImageStretch.setY(stretch->top); + m_vScrollImageStretch.setWidth(stretch->right - stretch->left); + m_vScrollImageStretch.setHeight(stretch->bottom - stretch->top); + } + } + else + { + delete img; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::setVScrollSliderImage(const QImage *normalImage, const HGRect *normalStretch, const QImage *hotImage, const HGRect *hotStretch, + const QImage *pushImage, const HGRect *pushStretch) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr == normalImage) + { + delete m_vScrollSliderImage[0]; + m_vScrollSliderImage[0] = nullptr; + } + else + { + QImage *img = new QImage(*normalImage); + if (!img->isNull()) + { + if (nullptr != m_vScrollSliderImage[0]) + delete m_vScrollSliderImage[0]; + m_vScrollSliderImage[0] = img; + + if (nullptr == normalStretch || normalStretch->left < 0 || normalStretch->top < 0 + || normalStretch->right > m_vScrollSliderImage[0]->width() || normalStretch->bottom > m_vScrollSliderImage[0]->height() + || normalStretch->left >= normalStretch->right || normalStretch->top >= normalStretch->bottom) + { + m_vScrollSliderImageStretch[0].setX(0); + m_vScrollSliderImageStretch[0].setY(0); + m_vScrollSliderImageStretch[0].setWidth(m_vScrollSliderImage[0]->width()); + m_vScrollSliderImageStretch[0].setHeight(m_vScrollSliderImage[0]->height()); + } + else + { + m_vScrollSliderImageStretch[0].setX(normalStretch->left); + m_vScrollSliderImageStretch[0].setY(normalStretch->top); + m_vScrollSliderImageStretch[0].setWidth(normalStretch->right - normalStretch->left); + m_vScrollSliderImageStretch[0].setHeight(normalStretch->bottom - normalStretch->top); + } + } + else + { + delete img; + } + } + + if (nullptr == hotImage) + { + delete m_vScrollSliderImage[1]; + m_vScrollSliderImage[1] = nullptr; + } + else + { + QImage *img = new QImage(*hotImage); + if (!img->isNull()) + { + if (nullptr != m_vScrollSliderImage[1]) + delete m_vScrollSliderImage[1]; + m_vScrollSliderImage[1] = img; + + if (nullptr == hotStretch || hotStretch->left < 0 || hotStretch->top < 0 + || hotStretch->right > m_vScrollSliderImage[1]->width() || hotStretch->bottom > m_vScrollSliderImage[1]->height() + || hotStretch->left >= hotStretch->right || hotStretch->top >= hotStretch->bottom) + { + m_vScrollSliderImageStretch[1].setX(0); + m_vScrollSliderImageStretch[1].setY(0); + m_vScrollSliderImageStretch[1].setWidth(m_vScrollSliderImage[1]->width()); + m_vScrollSliderImageStretch[1].setHeight(m_vScrollSliderImage[1]->height()); + } + else + { + m_vScrollSliderImageStretch[1].setX(hotStretch->left); + m_vScrollSliderImageStretch[1].setY(hotStretch->top); + m_vScrollSliderImageStretch[1].setWidth(hotStretch->right - hotStretch->left); + m_vScrollSliderImageStretch[1].setHeight(hotStretch->bottom - hotStretch->top); + } + } + else + { + delete img; + } + } + + if (nullptr == pushImage) + { + delete m_vScrollSliderImage[2]; + m_vScrollSliderImage[2] = nullptr; + } + else + { + QImage *img = new QImage(*pushImage); + if (!img->isNull()) + { + if (nullptr != m_vScrollSliderImage[2]) + delete m_vScrollSliderImage[2]; + m_vScrollSliderImage[2] = img; + + if (nullptr == pushStretch || pushStretch->left < 0 || pushStretch->top < 0 + || pushStretch->right > m_vScrollSliderImage[2]->width() || pushStretch->bottom > m_vScrollSliderImage[2]->height() + || pushStretch->left >= pushStretch->right || pushStretch->top >= hotStretch->bottom) + { + m_vScrollSliderImageStretch[2].setX(0); + m_vScrollSliderImageStretch[2].setY(0); + m_vScrollSliderImageStretch[2].setWidth(m_vScrollSliderImage[2]->width()); + m_vScrollSliderImageStretch[2].setHeight(m_vScrollSliderImage[2]->height()); + } + else + { + m_vScrollSliderImageStretch[2].setX(pushStretch->left); + m_vScrollSliderImageStretch[2].setY(pushStretch->top); + m_vScrollSliderImageStretch[2].setWidth(pushStretch->right - pushStretch->left); + m_vScrollSliderImageStretch[2].setHeight(pushStretch->bottom - pushStretch->top); + } + } + else + { + delete img; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::setNullScrollImage(const QImage *image) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr == image) + { + delete m_nullScrollImage; + m_nullScrollImage = nullptr; + } + else + { + QImage *img = new QImage(*image); + if (!img->isNull()) + { + if (nullptr != m_nullScrollImage) + delete m_nullScrollImage; + m_nullScrollImage = img; + } + else + { + delete img; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::enableScroll(bool enable) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + if (nullptr != m_image) + { + return HGBASE_ERR_FAIL; + } + + m_enableScroll = enable; + return HGBASE_ERR_OK; +} + +HGResult HGImgView::addImage(HGImage image) +{ + HGImage img = nullptr; + HGResult ret = HGBase_CloneImage(image, 0, HGBASE_IMGORIGIN_TOP, &img); + if (ret != HGBASE_ERR_OK) + { + return ret; + } + + reset(); + + if (nullptr != m_image) + { + delete m_qImage; + HGBase_DestroyImage(m_image); + } + + m_image = img; + m_qImage = createQImage(); + + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + HGRect rcWnd = {0, 0, this->width(), this->height()}; + + m_hScroll = false; + m_vScroll = false; + GetMinShowImageRect(&rcWnd, info.width, info.height, m_showImage, m_showRect); + double scale = (double)(m_showRect.right - m_showRect.left) / (double)info.width; + + updateMoveStatusAndCursor(); + Show(); + emit scaleChanged(scale); + return HGBASE_ERR_OK; +} + +HGResult HGImgView::clearImage() +{ + reset(); + + if (nullptr != m_image) + { + delete m_qImage; + m_qImage = nullptr; + HGBase_DestroyImage(m_image); + m_image = nullptr; + } + + m_hScroll = false; + m_vScroll = false; + m_showImage = false; + memset(&m_showRect, 0, sizeof(HGRectF)); + double scale = 0.0; + + updateMoveStatusAndCursor(); + Show(); + emit scaleChanged(scale); + return HGBASE_ERR_OK; +} + +HGResult HGImgView::getImage(HGImage *image) +{ + if (nullptr == image) + { + return HGBASE_ERR_INVALIDARG; + } + + *image = m_image; + return HGBASE_ERR_OK; +} + +HGResult HGImgView::rotateLeft() +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging || nullptr == m_image) + { + return HGBASE_ERR_FAIL; + } + + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + + HGImage img = nullptr; + HGResult ret = HGBase_CreateImage(info.height, info.width, info.type, HGBASE_IMGORIGIN_TOP, &img); + if (ret != HGBASE_ERR_OK) + { + return ret; + } + + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(m_image, &xDpi, &yDpi); + HGBase_SetImageDpi(img, xDpi, yDpi); + + HGBase_ImageRotateLeft(m_image, img); + + delete m_qImage; + HGBase_DestroyImage(m_image); + m_image = img; + m_qImage = createQImage(); + + HGBase_GetImageInfo(m_image, &info); + HGRect rcWnd = {0, 0, this->width(), this->height()}; + + m_hScroll = false; + m_vScroll = false; + GetMinShowImageRect(&rcWnd, info.width, info.height, m_showImage, m_showRect); + double scale = (double)(m_showRect.right - m_showRect.left) / (double)info.width; + + updateMoveStatusAndCursor(); + Show(); + emit scaleChanged(scale); + return HGBASE_ERR_OK; +} + +HGResult HGImgView::rotateRight() +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging || nullptr == m_image) + { + return HGBASE_ERR_FAIL; + } + + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + + HGImage img = nullptr; + HGResult ret = HGBase_CreateImage(info.height, info.width, info.type, HGBASE_IMGORIGIN_TOP, &img); + if (ret != HGBASE_ERR_OK) + { + return ret; + } + + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(m_image, &xDpi, &yDpi); + HGBase_SetImageDpi(img, xDpi, yDpi); + + HGBase_ImageRotateRight(m_image, img); + + delete m_qImage; + HGBase_DestroyImage(m_image); + m_image = img; + m_qImage = createQImage(); + + HGBase_GetImageInfo(m_image, &info); + HGRect rcWnd = {0, 0, this->width(), this->height()}; + + m_hScroll = false; + m_vScroll = false; + GetMinShowImageRect(&rcWnd, info.width, info.height, m_showImage, m_showRect); + double scale = (double)(m_showRect.right - m_showRect.left) / (double)info.width; + + updateMoveStatusAndCursor(); + Show(); + emit scaleChanged(scale); + return HGBASE_ERR_OK; +} + +HGResult HGImgView::rotate180() +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging || nullptr == m_image) + { + return HGBASE_ERR_FAIL; + } + + HGBase_ImageRotate180(m_image, m_image); + + delete m_qImage; + m_qImage = createQImage(); + + Show(); + return HGBASE_ERR_OK; +} + +HGResult HGImgView::zoomIn(const HGPoint *pCenter) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging || nullptr == m_image) + { + return HGBASE_ERR_FAIL; + } + + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + + // 获取最大值 + float fMaxWidth = info.width * 20.0f; + float fMaxHeight = info.height * 20.0f; + // 获取当前值 + float fCurWidth = m_showRect.right - m_showRect.left; + float fCurHeight = m_showRect.bottom - m_showRect.top; + // 新值 + float fNewWidth = fCurWidth * 1.2f; + float fNewHeight = fCurHeight * 1.2f; + + // support 1% zoom-in when 'ctrl' pressed (added on 2022-05-24) + if(QApplication::queryKeyboardModifiers() == Qt::CTRL) + { + // 1% + fNewWidth = info.width * .01f; + if(fNewWidth < 1.0f) + fNewWidth = 1.0f; + fNewWidth += fCurWidth; + + fNewHeight = info.height * .01f; + if(fNewHeight < 1.0f) + fNewHeight = 1.0f; + fNewHeight += fCurHeight; + } + + if (fabs(fMaxWidth - fCurWidth) > 1e-3 || fabs(fMaxHeight - fCurHeight) > 1e-3) + { + if (fNewWidth - fMaxWidth > -1e-3 || fNewHeight - fMaxHeight > -1e-3 + || round(100.0f * fNewWidth / (float)info.width) == round(100.0f * fMaxWidth / (float)info.width)) + { + fNewWidth = fMaxWidth; + fNewHeight = fMaxHeight; + } + + m_hScroll = false; + m_vScroll = false; + if (m_enableScroll) + { + if (fNewWidth > this->width()) + { + m_hScroll = true; + if (fNewHeight > this->height() - m_scrollSize) + m_vScroll = true; + } + else + { + if (fNewHeight > this->height()) + { + m_vScroll = true; + if (fNewWidth > this->width() - m_scrollSize) + m_hScroll = true; + } + } + } + + ResizeShowImageRect(m_showImage, m_showRect, fNewWidth, fNewHeight, pCenter); + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + double scale = (double)(m_showRect.right - m_showRect.left) / (double)info.width; + + updateMoveStatusAndCursor(); + Show(); + emit scaleChanged(scale); + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::zoomOut(const HGPoint *pCenter) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging || nullptr == m_image) + { + return HGBASE_ERR_FAIL; + } + + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + HGRect rcWnd = {0, 0, this->width(), this->height()}; + + // 获取最小值 + bool bMinShow; + HGRectF rcMinShow; + GetMinShowImageRect(&rcWnd, info.width, info.height, bMinShow, rcMinShow); + float fMinWidth = rcMinShow.right - rcMinShow.left; + float fMinHeight = rcMinShow.bottom - rcMinShow.top; + // 获取当前值 + float fCurWidth = m_showRect.right - m_showRect.left; + float fCurHeight = m_showRect.bottom - m_showRect.top; + // 新值 + float fNewWidth = fCurWidth * 1.0f / 1.2f; + float fNewHeight = fCurHeight * 1.0f / 1.2f; + + // support 1% zoom-out when 'ctrl' pressed (added on 2022-05-24) + if(QApplication::queryKeyboardModifiers() == Qt::CTRL) + { + // 1% + fNewWidth = info.width * .01f; + if(fNewWidth < 1.0f) + fNewWidth = 1.0f; + fNewWidth = fCurWidth - fNewWidth; + + fNewHeight = info.height * .01f; + if(fNewHeight < 1.0f) + fNewHeight = 1.0f; + fNewHeight = fCurHeight - fNewHeight; + } + + if (fabs(fMinWidth - fCurWidth) > 1e-3 || fabs(fMinHeight - fCurHeight) > 1e-3) + { + if (fNewWidth - fMinWidth < 1e-3 || fNewHeight - fMinHeight < 1e-3 + || round(100.0f * fNewWidth / (float)info.width) == round(100.0f * fMinWidth / (float)info.width)) + { + fNewWidth = fMinWidth; + fNewHeight = fMinHeight; + } + + m_hScroll = false; + m_vScroll = false; + if (m_enableScroll) + { + if (fNewWidth > this->width()) + { + m_hScroll = true; + if (fNewHeight > this->height() - m_scrollSize) + m_vScroll = true; + } + else + { + if (fNewHeight > this->height()) + { + m_vScroll = true; + if (fNewWidth > this->width() - m_scrollSize) + m_hScroll = true; + } + } + } + + ResizeShowImageRect(m_showImage, m_showRect, fNewWidth, fNewHeight, pCenter); + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + double scale = (double)(m_showRect.right - m_showRect.left) / (double)info.width; + + updateMoveStatusAndCursor(); + Show(); + emit scaleChanged(scale); + } + + return HGBASE_ERR_OK; +} + +HGResult HGImgView::realSize() +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging || nullptr == m_image) + { + return HGBASE_ERR_FAIL; + } + + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + + m_hScroll = false; + m_vScroll = false; + if (m_enableScroll) + { + if ((int)info.width > this->width()) + { + m_hScroll = true; + if ((int)info.height > this->height() - m_scrollSize) + m_vScroll = true; + } + else + { + if ((int)info.height > this->height()) + { + m_vScroll = true; + if ((int)info.width > this->width() - m_scrollSize) + m_hScroll = true; + } + } + } + + ResizeShowImageRect(m_showImage, m_showRect, (float)info.width, (float)info.height, nullptr); + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + double scale = 1.0; + + updateMoveStatusAndCursor(); + Show(); + emit scaleChanged(scale); + return HGBASE_ERR_OK; +} + +HGResult HGImgView::fitWndSize() +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging || nullptr == m_image) + { + return HGBASE_ERR_FAIL; + } + + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + HGRect rcWnd = {0, 0, this->width(), this->height()}; + + m_hScroll = false; + m_vScroll = false; + GetMinShowImageRect(&rcWnd, info.width, info.height, m_showImage, m_showRect); + double scale = (double)(m_showRect.right - m_showRect.left) / (double)info.width; + + updateMoveStatusAndCursor(); + Show(); + emit scaleChanged(scale); + return HGBASE_ERR_OK; +} + +HGResult HGImgView::fitWndWidth() +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging || nullptr == m_image) + { + return HGBASE_ERR_FAIL; + } + + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + HGRect rcWnd = {0, 0, this->width(), this->height()}; + + // 获取最小值 + bool bMinShow; + HGRectF rcMinShow; + GetMinShowImageRect(&rcWnd, info.width, info.height, bMinShow, rcMinShow); + float fMinWidth = rcMinShow.right - rcMinShow.left; + float fMinHeight = rcMinShow.bottom - rcMinShow.top; + // 获取最大值 + float fMaxWidth = info.width * 20.0f; + float fMaxHeight = info.height * 20.0f; + // 新值 + float fNewWidth = (float)this->width(); + float fNewHeight = fNewWidth * (float)info.height / (float)info.width; + fNewWidth = HGMIN(fMaxWidth, HGMAX(fMinWidth, fNewWidth)); + fNewHeight = HGMIN(fMaxHeight, HGMAX(fMinHeight, fNewHeight)); + + m_hScroll = false; + m_vScroll = false; + if (m_enableScroll) + { + if (fNewHeight > this->height()) + { + m_vScroll = true; + fNewWidth = this->width() - m_scrollSize; + fNewHeight = fNewWidth * (float)info.height / (float)info.width; + fNewWidth = HGMIN(fMaxWidth, HGMAX(fMinWidth, fNewWidth)); + fNewHeight = HGMIN(fMaxHeight, HGMAX(fMinHeight, fNewHeight)); + + if (fNewHeight <= this->height()) + { + m_vScroll = false; + fNewWidth = (float)this->width(); + fNewHeight = fNewWidth * (float)info.height / (float)info.width; + fNewWidth = HGMIN(fMaxWidth, HGMAX(fMinWidth, fNewWidth)); + fNewHeight = HGMIN(fMaxHeight, HGMAX(fMinHeight, fNewHeight)); + } + } + } + + ResizeShowImageRect(m_showImage, m_showRect, fNewWidth, fNewHeight, nullptr); + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + double scale = (double)(m_showRect.right - m_showRect.left) / (double)info.width; + + updateMoveStatusAndCursor(); + Show(); + emit scaleChanged(scale); + return HGBASE_ERR_OK; +} + +HGResult HGImgView::showColorInfo(bool show) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return HGBASE_ERR_FAIL; + } + + m_showColorInfo = show; + QToolTip::hideText(); + updateMoveStatusAndCursor(); + return HGBASE_ERR_OK; +} + +void HGImgView::mousePressEvent(QMouseEvent* e) +{ + if (e->button() != Qt::LeftButton) + { + return; + } + + MouseStatus mouseStatus = getMouseStatus(e->pos()); + if (MouseStatus_Null != mouseStatus) + { + // 如果鼠标点到滚动条区域 + m_mousePressStatus = mouseStatus; + m_mousePressBeginX = e->pos().x(); + m_mousePressBeginY = e->pos().y(); + updateMoveStatusAndCursor(); + Show(); + return; + } + + assert(0 == m_operate); + if (nullptr == m_image || !m_showImage) + { + return; + } + + m_operate = 1; + m_beginX = e->pos().x(); + m_beginY = e->pos().y(); + updateMoveStatusAndCursor(); +} + +void HGImgView::mouseMoveEvent(QMouseEvent* e) +{ + // 处理滚动条 + if (MouseStatus_HScrollSlider == m_mousePressStatus) + { + int lXAmount = e->pos().x() - m_mousePressBeginX; + double offset; + if (!m_vScroll) + { + int rollTotalLen = this->width() - 2 * m_scrollSize; + int rollLeft = round((double)rollTotalLen * (-m_showRect.left) / (double)(m_showRect.right - m_showRect.left)); + int rollRight = round((double)rollTotalLen * (-m_showRect.left + this->width()) / (double)(m_showRect.right - m_showRect.left)); + int rollLen = rollRight - rollLeft; + if (rollLen >= m_minScrollSliderSize) + offset = lXAmount * (m_showRect.right - m_showRect.left) / rollTotalLen; + else + offset = lXAmount * (m_showRect.right - m_showRect.left - this->width()) / (rollTotalLen - m_minScrollSliderSize); + } + else + { + int rollTotalLen = this->width() - 3 * m_scrollSize; + int rollLeft = round((double)rollTotalLen * (-m_showRect.left) / (double)(m_showRect.right - m_showRect.left)); + int rollRight = round((double)rollTotalLen * (-m_showRect.left + this->width() - m_scrollSize) / (double)(m_showRect.right - m_showRect.left)); + int rollLen = rollRight - rollLeft; + if (rollLen >= m_minScrollSliderSize) + offset = lXAmount * (m_showRect.right - m_showRect.left) / rollTotalLen; + else + offset = lXAmount * (m_showRect.right - m_showRect.left - this->width() + m_scrollSize) / (rollTotalLen - m_minScrollSliderSize); + } + m_showRect.left -= offset; + m_showRect.right -= offset; + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + + Show(); + m_mousePressBeginX = e->pos().x(); + m_mousePressBeginY = e->pos().y(); + } + else if (MouseStatus_VScrollSlider == m_mousePressStatus) + { + int lYAmount = e->pos().y() - m_mousePressBeginY; + double offset; + if (!m_hScroll) + { + int rollTotalLen = this->height() - 2 * m_scrollSize; + int rollTop = round((double)rollTotalLen * (-m_showRect.top) / (double)(m_showRect.bottom - m_showRect.top)); + int rollBottom = round((double)rollTotalLen * (-m_showRect.top + this->height()) / (double)(m_showRect.bottom - m_showRect.top)); + int rollLen = rollBottom - rollTop; + if (rollLen >= m_minScrollSliderSize) + offset = lYAmount * (m_showRect.bottom - m_showRect.top) / rollTotalLen; + else + offset = lYAmount * (m_showRect.bottom - m_showRect.top - this->height()) / (rollTotalLen - m_minScrollSliderSize); + } + else + { + int rollTotalLen = this->height() - 3 * m_scrollSize; + int rollTop = round((double)rollTotalLen * (-m_showRect.top) / (double)(m_showRect.bottom - m_showRect.top)); + int rollBottom = round((double)rollTotalLen * (-m_showRect.top + this->height() - m_scrollSize) / (double)(m_showRect.bottom - m_showRect.top)); + int rollLen = rollBottom - rollTop; + if (rollLen >= m_minScrollSliderSize) + offset = lYAmount * (m_showRect.bottom - m_showRect.top) / rollTotalLen; + else + offset = lYAmount * (m_showRect.bottom - m_showRect.top - this->height() + m_scrollSize) / (rollTotalLen - m_minScrollSliderSize); + } + m_showRect.top -= offset; + m_showRect.bottom -= offset; + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + + Show(); + m_mousePressBeginX = e->pos().x(); + m_mousePressBeginY = e->pos().y(); + } + + if (1 == m_operate) + { + assert(nullptr != m_image && m_showImage); + + int lXAmount = e->pos().x() - m_beginX; + int lYAmount = e->pos().y() - m_beginY; + + m_showRect.left += lXAmount; + m_showRect.right += lXAmount; + m_showRect.top += lYAmount; + m_showRect.bottom += lYAmount; + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + + Show(); + m_beginX = e->pos().x(); + m_beginY = e->pos().y(); + } + else + { + assert(0 == m_operate); + + MouseStatus mouseStatus = getMouseStatus(e->pos()); + if (nullptr != m_image && m_showImage && !m_draging + && MouseStatus_Null == m_mousePressStatus && MouseStatus_Null == mouseStatus) + { + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + + int xShow = e->pos().x() - m_showRect.left; + int yShow = e->pos().y() - m_showRect.top; + int xImg = xShow * (int)info.width / (m_showRect.right - m_showRect.left); + int yImg = yShow * (int)info.height / (m_showRect.bottom - m_showRect.top); + + if (xImg >= 0 && xImg < (int)info.width && yImg >= 0 && yImg < (int)info.height) + { + //qDebug("mousePos, x=%d, y=%d", xImg, yImg); + emit mousePos(xImg, yImg); + + if (m_showColorInfo) + { + HGByte *data = nullptr; + HGBase_GetImageData(m_image, &data); + HGByte *pixel = data + yImg * info.widthStep + xImg * 3; + + HGByte r = pixel[0]; + HGByte g = pixel[1]; + HGByte b = pixel[2]; + //qDebug("colorInfo, r=%d, g=%d, b=%d", r, g, b); + + char colorInfo[1024]; + sprintf(colorInfo, "X: %d, Y: %d\nRGB(%d, %d, %d)\nHTML(#%02X%02X%02X)", + xImg, yImg, r, g, b, r, g, b); + QToolTip::showText(e->globalPos(), colorInfo, this); + } + } + else + { + emit mousePos(0, 0); + QToolTip::hideText(); + } + } + else + { + emit mousePos(0, 0); + QToolTip::hideText(); + } + + updateMoveStatusAndCursor(); + Show(); + } +} + +void HGImgView::mouseReleaseEvent(QMouseEvent* e) +{ + Q_UNUSED(e); + + m_draging = false; + + m_beginX = -1; + m_beginY = -1; + m_operate = 0; + + MouseStatus oldMousePressStatus = m_mousePressStatus; + m_mousePressStatus = MouseStatus_Null; + m_mousePressBeginX = -1; + m_mousePressBeginY = -1; + + // 处理按滚动条区域 + MouseStatus mouseMoveStatus = getMouseStatus(e->pos()); + if (MouseStatus_HScrollLeft == oldMousePressStatus && MouseStatus_HScrollLeft == mouseMoveStatus) + { + double width = m_showRect.right - m_showRect.left; + m_showRect.left += width / 10.0; + m_showRect.right += width / 10.0; + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + } + else if (MouseStatus_HScrollRight == oldMousePressStatus && MouseStatus_HScrollRight == mouseMoveStatus) + { + double width = m_showRect.right - m_showRect.left; + m_showRect.left -= width / 10.0; + m_showRect.right -= width / 10.0; + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + } + else if (MouseStatus_VScrollTop == oldMousePressStatus && MouseStatus_VScrollTop == mouseMoveStatus) + { + double height = m_showRect.bottom - m_showRect.top; + m_showRect.top += height / 10.0; + m_showRect.bottom += height / 10.0; + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + } + else if (MouseStatus_VScrollBottom == oldMousePressStatus && MouseStatus_VScrollBottom == mouseMoveStatus) + { + double height = m_showRect.bottom - m_showRect.top; + m_showRect.top -= height / 10.0; + m_showRect.bottom -= height / 10.0; + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + } + + updateMoveStatusAndCursor(); + Show(); +} + +void HGImgView::enterEvent(QEvent *e) +{ + Q_UNUSED(e); + m_mouseOn = true; +} + +void HGImgView::leaveEvent(QEvent *e) +{ + Q_UNUSED(e); + + // 拖动状态不能重置 + //m_draging = false; + + m_operate = 0; + m_beginX = -1; + m_beginY = -1; + + m_mouseOn = false; + m_mouseMoveStatus = MouseStatus_Null; + Show(); + emit mousePos(0, 0); +} + +void HGImgView::paintEvent(QPaintEvent* e) +{ + Q_UNUSED(e); + + QPainter painter(this); + painter.fillRect(0, 0, this->width(), this->height(), qRgb(250, 250, 250)); + + if (nullptr == m_qImage || !m_showImage) + { + return; + } + +#if 0 + HGRect rcWnd = {0, 0, this->width(), this->height()}; + int nImgWidth = info.width; + int nImgHeight = info.height; + + // 绘制Image + int xDest, yDest, wDest, hDest; + int xSrc, ySrc, wSrc, hSrc; + + HGRect rcShowImage; // 绘制的图像区域 + rcShowImage.left = round(m_showRect.left); + rcShowImage.top = round(m_showRect.top); + rcShowImage.right = round(m_showRect.right); + rcShowImage.bottom = round(m_showRect.bottom); + int nShowWidth = rcShowImage.right - rcShowImage.left; + int nShowHeight = rcShowImage.bottom - rcShowImage.top; + + if (rcShowImage.left <= rcWnd.left) + { + float fPixel = (float)nImgWidth * (rcWnd.left - rcShowImage.left) / nShowWidth; + float fPixelR = (float)nImgWidth * (rcShowImage.right - rcWnd.right) / nShowWidth; + xDest = rcShowImage.left + round((int)fPixel * (float)nShowWidth / nImgWidth); + int xDestR = rcShowImage.right - round((int)fPixelR * (float)nShowWidth / nImgWidth); + wDest = xDestR - xDest; + wSrc = round((float)nImgWidth * wDest / nShowWidth); + xSrc = round((float)(xDest - rcShowImage.left) * nImgWidth / nShowWidth); + } + else + { + xDest = rcShowImage.left; + wDest = nShowWidth; + xSrc = 0; + wSrc = nImgWidth; + } + + if (rcShowImage.top <= rcWnd.top) + { + float fPixel = (float)nImgHeight * (rcWnd.top - rcShowImage.top) / nShowHeight; + float fPixelB = (float)nImgHeight * (rcShowImage.bottom - rcWnd.bottom) / nShowHeight; + yDest = rcShowImage.top + round((int)fPixel * (float)nShowHeight / nImgHeight); + int yDestB = rcShowImage.bottom - round((int)fPixelB * (float)nShowHeight / nImgHeight); + hDest = yDestB - yDest; + hSrc = round((float)nImgHeight * hDest / nShowHeight); + ySrc = round((float)(yDest - rcShowImage.top) * nImgHeight / nShowHeight); + } + else + { + yDest = rcShowImage.top; + hDest = nShowHeight; + ySrc = 0; + hSrc = nImgHeight; + } + + QRect srcRect(xSrc, ySrc, wSrc, hSrc); + QRect destRect(xDest, yDest, wDest, hDest); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + painter.drawImage(destRect, *m_qImage, srcRect); +#else + QRectF destRect(m_showRect.left, m_showRect.top, m_showRect.right - m_showRect.left, m_showRect.bottom - m_showRect.top); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + painter.drawImage(destRect, *m_qImage); +#endif + + DrawScroll(painter); +} + +void HGImgView::wheelEvent(QWheelEvent* e) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return; + } + + MouseStatus mouseStatus = getMouseStatus(e->pos()); + if (MouseStatus_Null != mouseStatus) + { + if (MouseStatus_HScroll == mouseStatus || MouseStatus_HScrollSlider == mouseStatus + || MouseStatus_HScrollLeft == mouseStatus || MouseStatus_HScrollRight == mouseStatus) + { + double width = m_showRect.right - m_showRect.left; + + if (e->delta() > 0) + { + m_showRect.left += width / 10.0; + m_showRect.right += width / 10.0; + } + else + { + m_showRect.left -= width / 10.0; + m_showRect.right -= width / 10.0; + } + + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + } + else if (MouseStatus_VScroll == mouseStatus || MouseStatus_VScrollSlider == mouseStatus + || MouseStatus_VScrollTop == mouseStatus || MouseStatus_VScrollBottom == mouseStatus) + { + double height = m_showRect.bottom - m_showRect.top; + + if (e->delta() > 0) + { + m_showRect.top += height / 10.0; + m_showRect.bottom += height / 10.0; + } + else + { + m_showRect.top -= height / 10.0; + m_showRect.bottom -= height / 10.0; + } + + recalcShowRect(this->width(), this->height(), m_scrollSize, m_hScroll, m_vScroll, m_showImage, m_showRect); + } + + Show(); + return; + } + + HGPoint pt = {e->pos().x(), e->pos().y()}; + + if (e->delta() > 0) + zoomIn(&pt); + else + zoomOut(&pt); +} + +void HGImgView::resizeEvent(QResizeEvent* e) +{ + Q_UNUSED(e); + + reset(); + + if (nullptr != m_image) + { + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + HGRect rcWnd = {0, 0, this->width(), this->height()}; + + m_hScroll = false; + m_vScroll = false; + GetMinShowImageRect(&rcWnd, info.width, info.height, m_showImage, m_showRect); + double scale = (double)(m_showRect.right - m_showRect.left) / (double)info.width; + + emit scaleChanged(scale); + } + + updateMoveStatusAndCursor(); + Show(); +} + +void HGImgView::keyPressEvent(QKeyEvent *e) +{ + Q_UNUSED(e); + + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return; + } + + if (e->key() == Qt::Key_Escape) + { + emit escape(); + } +} + +void HGImgView::dragEnterEvent(QDragEnterEvent *e) +{ + qDebug("dragEnterEvent"); + + if (e->mimeData()->hasUrls()) + { + m_draging = true; + e->accept(); + } +} + +void HGImgView::dragMoveEvent(QDragMoveEvent *e) +{ + //qDebug("dragMoveEvent"); + Q_UNUSED(e); + + //Show(); +} + +void HGImgView::dragLeaveEvent(QDragLeaveEvent *e) +{ + qDebug("dragLeaveEvent"); + Q_UNUSED(e); + + m_draging = false; + //Show(); +} + +void HGImgView::dropEvent(QDropEvent *e) +{ + Q_UNUSED(e); + + QStringList fileNames; + QList urls = e->mimeData()->urls(); + for (QUrl url : urls) + { + fileNames.append(url.toLocalFile()); + } + + m_draging = false; + emit drop(e->source(), fileNames); +} + +void HGImgView::mouseDoubleClickEvent(QMouseEvent* e) +{ + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return; + } + + MouseStatus mouseMoveStatus = getMouseStatus(e->pos()); + if (MouseStatus_Null == mouseMoveStatus) + { + emit doubleClicked(); + } + else + { + QWidget::mouseDoubleClickEvent(e); + } +} + +void HGImgView::GetMinShowImageRect(const HGRect *pWnd, int nImgWidth, int nImgHeight, bool &bShowImage, HGRectF &rcShowImage) +{ + bShowImage = false; + memset(&rcShowImage, 0, sizeof(HGRectF)); + + assert(nullptr != pWnd); + + int nWndWidth = pWnd->right - pWnd->left; + int nWndHeight = pWnd->bottom - pWnd->top; + if (nWndWidth <= 0 || nWndHeight <= 0) + { + return; + } + + if (nImgWidth <= 0 || nImgHeight <= 0) + { + return; + } + + float fLeft, fTop, fRight, fBottom; + + if (nImgWidth > nWndWidth || nImgHeight > nWndHeight) + { + if (nImgWidth * nWndHeight < nImgHeight * nWndWidth) + { + float fWidth = (float)nWndHeight * nImgWidth / nImgHeight; + fLeft = (pWnd->left + pWnd->right - fWidth) / 2.0f; + fRight = (pWnd->left + pWnd->right + fWidth) / 2.0f; + fTop = (float)pWnd->top; + fBottom = (float)pWnd->bottom; + } + else + { + float fHeight = (float)nWndWidth * nImgHeight / nImgWidth; + fLeft = (float)pWnd->left; + fRight = (float)pWnd->right; + fTop = (pWnd->top + pWnd->bottom - fHeight) / 2.0f; + fBottom = (pWnd->top + pWnd->bottom + fHeight) / 2.0f; + } + } + else + { + fLeft = (pWnd->left + pWnd->right - nImgWidth) / 2.0f; + fRight = (pWnd->left + pWnd->right + nImgWidth) / 2.0f; + fTop = (pWnd->top + pWnd->bottom - nImgHeight) / 2.0f; + fBottom = (pWnd->top + pWnd->bottom + nImgHeight) / 2.0f; + } + + if (fRight - fLeft < 1e-3 || fBottom - fTop < 1e-3) + { + return; + } + + bShowImage = true; + rcShowImage.left = fLeft; + rcShowImage.top = fTop; + rcShowImage.right = fRight; + rcShowImage.bottom = fBottom; +} + +void HGImgView::ResizeShowImageRect(bool &bShowImage, HGRectF &rcShowImage, float fNewWidth, float fNewHeight, const HGPoint *pCenter) +{ + if (!bShowImage) + { + return; + } + + if (fNewWidth <= 0 || fNewHeight <= 0) + { + bShowImage = false; + memset(&rcShowImage, 0, sizeof(HGRectF)); + return; + } + + float fCurWidth = rcShowImage.right - rcShowImage.left; + float fCurHeight = rcShowImage.bottom - rcShowImage.top; + + if (nullptr != pCenter) + { + rcShowImage.left = (float)pCenter->x - ((float)pCenter->x - rcShowImage.left) * fNewWidth / fCurWidth; + rcShowImage.top = (float)pCenter->y - ((float)pCenter->y - rcShowImage.top) * fNewHeight / fCurHeight; + } + else + { + rcShowImage.left = rcShowImage.left - (fNewWidth - fCurWidth) / 2.0f; + rcShowImage.top = rcShowImage.top - (fNewHeight - fCurHeight) / 2.0f; + } + + rcShowImage.right = rcShowImage.left + fNewWidth; + rcShowImage.bottom = rcShowImage.top + fNewHeight; + + if (rcShowImage.right - rcShowImage.left < 1e-3 || rcShowImage.bottom - rcShowImage.top < 1e-3) + { + bShowImage = false; + memset(&rcShowImage, 0, sizeof(HGRectF)); + } +} + +void HGImgView::recalcShowRect(int wndWidth, int wndHeight, int scrollSize, bool hScroll, bool vScroll, bool showImage, HGRectF &imageRect) +{ + if (!showImage) + return; + + double width = imageRect.right - imageRect.left; + double height = imageRect.bottom - imageRect.top; + + int vScorllSize = vScroll ? scrollSize : 0; + if (width <= (double)(wndWidth - vScorllSize)) + { + imageRect.left = (wndWidth - vScorllSize - width) / 2.0; + imageRect.right = imageRect.left + width; + } + else + { + if (imageRect.right < (double)(wndWidth - vScorllSize)) + { + imageRect.right = wndWidth - vScorllSize; + imageRect.left = imageRect.right - width; + } + if (imageRect.left > 0) + { + imageRect.left = 0; + imageRect.right = imageRect.left + width; + } + } + + int hScorllSize = hScroll ? scrollSize : 0; + if (height <= (double)(wndHeight - hScorllSize)) + { + imageRect.top = (wndHeight - hScorllSize - height) / 2.0; + imageRect.bottom = imageRect.top + height; + } + else + { + if (imageRect.bottom < (double)(wndHeight - hScorllSize)) + { + imageRect.bottom = wndHeight - hScorllSize; + imageRect.top = imageRect.bottom - height; + } + if (imageRect.top > 0) + { + imageRect.top = 0; + imageRect.bottom = imageRect.top + height; + } + } +} + +void HGImgView::DrawImage(QPainter &painter, const QRect &destRect, const QImage *image, const QRect &stretchRect) +{ + if (destRect.width() < image->width() - stretchRect.width() + || destRect.height() < image->height() - stretchRect.height()) + { + painter.drawImage(destRect, *image); + return; + } + + for (int i = 0; i < 9; ++i) + { + int DestX = destRect.left(), DestY = destRect.top(), DestWidth = destRect.width(), DestHeight = destRect.height(); + int SrcX = 0, SrcY = 0, SrcWidth = image->width(), SrcHeight = image->height(); + + if (0 == i % 3) + { + DestX = destRect.left(); + DestWidth = stretchRect.left(); + SrcX = 0; + SrcWidth = stretchRect.left(); + } + else if (1 == i % 3) + { + DestX = destRect.left() + stretchRect.left(); + DestWidth = destRect.width() + stretchRect.width() - image->width(); + SrcX = stretchRect.left(); + SrcWidth = stretchRect.width(); + } + else if (2 == i % 3) + { + DestX = destRect.left() + destRect.width() + stretchRect.left() + stretchRect.width() - image->width(); + DestWidth = image->width() - (stretchRect.left() + stretchRect.width()); + SrcX = stretchRect.left() + stretchRect.width(); + SrcWidth = image->width() - (stretchRect.left() + stretchRect.width()); + } + + if (0 == i / 3) + { + DestY = destRect.top(); + DestHeight = stretchRect.top(); + SrcY = 0; + SrcHeight = stretchRect.top(); + } + else if (1 == i / 3) + { + DestY = destRect.top() + stretchRect.top(); + DestHeight = destRect.height() + stretchRect.height() - image->height(); + SrcY = stretchRect.top(); + SrcHeight = stretchRect.height(); + } + else if (2 == i / 3) + { + DestY = destRect.top() + destRect.height() + stretchRect.top() + stretchRect.height() - image->height(); + DestHeight = image->height() - (stretchRect.top() + stretchRect.height()); + SrcY = stretchRect.top() + stretchRect.height(); + SrcHeight = image->height() - (stretchRect.top() + stretchRect.height()); + } + + QRect dest(DestX, DestY, DestWidth, DestHeight); + QRect src(SrcX, SrcY, SrcWidth, SrcHeight); + painter.drawImage(dest, *image, src); + } +} + +QImage* HGImgView::createQImage() +{ + if (nullptr == m_image) + return nullptr; + + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + + QImage::Format fmt = QImage::Format_Invalid; + if (info.type == HGBASE_IMGTYPE_BINARY) + fmt = QImage::Format_Mono; + else if (info.type == HGBASE_IMGTYPE_GRAY) + fmt = QImage::Format_Grayscale8; + else if (info.type == HGBASE_IMGTYPE_RGB) + fmt = QImage::Format_RGB888; + else if (info.type == HGBASE_IMGTYPE_RGBA) + fmt = QImage::Format_RGBA8888; + if (QImage::Format_Invalid == fmt) + { + return nullptr; + } + + HGByte* data = nullptr; + HGBase_GetImageData(m_image, &data); + QImage* img = new QImage(data, info.width, info.height, info.widthStep, fmt); + if (img->isNull()) + { + delete img; + return nullptr; + } + + if (img->format() != QImage::Format_Mono) + { + return img; + } + + QImage *newImg = new QImage(img->convertToFormat(QImage::Format_Grayscale8)); + delete img; + return newImg; +} + +void HGImgView::DrawScroll(QPainter &painter) +{ + // 滚动条背景 + QColor clrHScroll = qRgb(220, 220, 220); + QImage *imgHScroll = m_hScrollImage; + QColor clrVScroll = qRgb(220, 220, 220); + QImage *imgVScroll = m_vScrollImage; + QColor clrNullScroll = qRgb(255, 255, 255); + QImage *nullScrollImage = m_nullScrollImage; + + // 水平滑块 + QColor clrHScrollSlider = qRgb(180, 180, 180); + QImage *imgHScrollSlider = m_hScrollSliderImage[0]; + QRect hScrollSliderStretch = m_hScrollSliderImageStretch[0]; + if (MouseStatus_HScrollSlider == m_mousePressStatus) + { + clrHScrollSlider = qRgb(100, 100, 100); + imgHScrollSlider = m_hScrollSliderImage[2]; + hScrollSliderStretch = m_hScrollSliderImageStretch[2]; + } + else if (MouseStatus_HScrollLeft == m_mousePressStatus || MouseStatus_HScrollRight == m_mousePressStatus + || MouseStatus_HScroll == m_mousePressStatus + || MouseStatus_HScrollSlider == m_mouseMoveStatus || MouseStatus_HScroll == m_mouseMoveStatus + || MouseStatus_HScrollLeft == m_mouseMoveStatus || MouseStatus_HScrollRight == m_mouseMoveStatus) + { + clrHScrollSlider = qRgb(140, 140, 140); + imgHScrollSlider = m_hScrollSliderImage[1]; + hScrollSliderStretch = m_hScrollSliderImageStretch[1]; + } + + // 垂直滑块 + QColor clrVScrollSlider = qRgb(180, 180, 180); + QImage *imgVScrollSlider = m_vScrollSliderImage[0]; + QRect vScrollSliderStretch = m_vScrollSliderImageStretch[0]; + if (MouseStatus_VScrollSlider == m_mousePressStatus) + { + clrVScrollSlider = qRgb(100, 100, 100); + imgVScrollSlider = m_vScrollSliderImage[2]; + vScrollSliderStretch = m_vScrollSliderImageStretch[2]; + } + else if (MouseStatus_VScrollTop == m_mousePressStatus || MouseStatus_VScrollBottom == m_mousePressStatus + || MouseStatus_VScroll == m_mousePressStatus + || MouseStatus_VScrollSlider == m_mouseMoveStatus || MouseStatus_VScroll == m_mouseMoveStatus + || MouseStatus_VScrollTop == m_mouseMoveStatus || MouseStatus_VScrollBottom == m_mouseMoveStatus) + { + clrVScrollSlider = qRgb(140, 140, 140); + imgVScrollSlider = m_vScrollSliderImage[1]; + vScrollSliderStretch = m_vScrollSliderImageStretch[1]; + } + + // 水平左键 + QColor clrHScrollLeft = qRgb(220, 220, 220); + QImage *imgHScrollLeft = m_hScrollLeftImage[0]; + if (MouseStatus_HScrollLeft == m_mousePressStatus) + { + clrHScrollLeft = qRgb(140, 140, 140); + imgHScrollLeft = m_hScrollLeftImage[2]; + } + else if (MouseStatus_HScrollRight == m_mousePressStatus || MouseStatus_HScrollSlider == m_mousePressStatus + || MouseStatus_HScroll == m_mousePressStatus + || MouseStatus_HScrollSlider == m_mouseMoveStatus || MouseStatus_HScroll == m_mouseMoveStatus + || MouseStatus_HScrollLeft == m_mouseMoveStatus || MouseStatus_HScrollRight == m_mouseMoveStatus) + { + clrHScrollLeft = qRgb(180, 180, 180); + imgHScrollLeft = m_hScrollLeftImage[1]; + } + + // 水平右键 + QColor clrHScrollRight = qRgb(220, 220, 220); + QImage *imgHScrollRight = m_hScrollRightImage[0]; + if (MouseStatus_HScrollRight == m_mousePressStatus) + { + clrHScrollRight = qRgb(140, 140, 140); + imgHScrollRight = m_hScrollRightImage[2]; + } + else if (MouseStatus_HScrollLeft == m_mousePressStatus || MouseStatus_HScrollSlider == m_mousePressStatus + || MouseStatus_HScroll == m_mousePressStatus + || MouseStatus_HScrollSlider == m_mouseMoveStatus || MouseStatus_HScroll == m_mouseMoveStatus + || MouseStatus_HScrollLeft == m_mouseMoveStatus || MouseStatus_HScrollRight == m_mouseMoveStatus) + { + clrHScrollRight = qRgb(180, 180, 180); + imgHScrollRight = m_hScrollRightImage[1]; + } + + // 垂直上键 + QColor clrVScrollTop = qRgb(220, 220, 220); + QImage *imgVScrollTop = m_vScrollTopImage[0]; + if (MouseStatus_VScrollTop == m_mousePressStatus) + { + clrVScrollTop = qRgb(140, 140, 140); + imgVScrollTop = m_vScrollTopImage[2]; + } + else if (MouseStatus_VScrollSlider == m_mousePressStatus || MouseStatus_VScrollBottom == m_mousePressStatus + || MouseStatus_VScroll == m_mousePressStatus + || MouseStatus_VScrollSlider == m_mouseMoveStatus || MouseStatus_VScroll == m_mouseMoveStatus + || MouseStatus_VScrollTop == m_mouseMoveStatus || MouseStatus_VScrollBottom == m_mouseMoveStatus) + { + clrVScrollTop = qRgb(180, 180, 180); + imgVScrollTop = m_vScrollTopImage[1]; + } + + // 垂直下键 + QColor clrVScrollBottom = qRgb(220, 220, 220); + QImage *imgVScrollBottom = m_vScrollBottomImage[0]; + if (MouseStatus_VScrollBottom == m_mousePressStatus) + { + clrVScrollBottom = qRgb(140, 140, 140); + imgVScrollBottom = m_vScrollBottomImage[2]; + } + else if (MouseStatus_VScrollSlider == m_mousePressStatus || MouseStatus_VScrollTop == m_mousePressStatus + || MouseStatus_VScroll == m_mousePressStatus + || MouseStatus_VScrollSlider == m_mouseMoveStatus || MouseStatus_VScroll == m_mouseMoveStatus + || MouseStatus_VScrollTop == m_mouseMoveStatus || MouseStatus_VScrollBottom == m_mouseMoveStatus) + { + clrVScrollBottom = qRgb(180, 180, 180); + imgVScrollBottom = m_vScrollBottomImage[1]; + } + + if (m_hScroll) + { + if (nullptr == imgHScroll) + painter.fillRect(getHScrollPos(), clrHScroll); + else + DrawImage(painter, getHScrollPos(), imgHScroll, m_hScrollImageStretch); + + if (nullptr == imgHScrollLeft) + painter.fillRect(getHScrollLeftPos(), clrHScrollLeft); + else + painter.drawImage(getHScrollLeftPos(), *imgHScrollLeft); + + if (nullptr == imgHScrollRight) + painter.fillRect(getHScrollRightPos(), clrHScrollRight); + else + painter.drawImage(getHScrollRightPos(), *imgHScrollRight); + + if (nullptr == imgHScrollSlider) + painter.fillRect(getHScrollSliderPos(), clrHScrollSlider); + else + DrawImage(painter, getHScrollSliderPos(), imgHScrollSlider, hScrollSliderStretch); + } + + if (m_vScroll) + { + if (nullptr == imgVScroll) + painter.fillRect(getVScrollPos(), clrVScroll); + else + DrawImage(painter, getVScrollPos(), imgVScroll, m_vScrollImageStretch); + + if (nullptr == imgVScrollTop) + painter.fillRect(getVScrollTopPos(), clrVScrollTop); + else + painter.drawImage(getVScrollTopPos(), *imgVScrollTop); + + if (nullptr == imgVScrollBottom) + painter.fillRect(getVScrollBottomPos(), clrVScrollBottom); + else + painter.drawImage(getVScrollBottomPos(), *imgVScrollBottom); + + if (nullptr == imgVScrollSlider) + painter.fillRect(getVScrollSliderPos(), clrVScrollSlider); + else + DrawImage(painter, getVScrollSliderPos(), imgVScrollSlider, vScrollSliderStretch); + } + + if (m_hScroll && m_vScroll) + { + if (nullptr == nullScrollImage) + painter.fillRect(getNullScrollPos(), clrNullScroll); + else + painter.drawImage(getNullScrollPos(), *nullScrollImage); + } +} + +void HGImgView::reset() +{ + // 复位 + m_draging = false; + + m_operate = 0; + m_beginX = -1; + m_beginY = -1; +} + +void HGImgView::updateMoveStatusAndCursor() +{ + m_mouseMoveStatus = getMouseStatus(mapFromGlobal(QCursor::pos())); + + if (0 != m_operate) + { + setCursor(Qt::ClosedHandCursor); + } + else if (MouseStatus_Null != m_mousePressStatus || m_draging) + { + setCursor(Qt::ArrowCursor); + } + else + { + QRect rcWnd(0, 0, this->width(), this->height()); + if (nullptr == m_image || !m_showImage + || !m_showColorInfo || MouseStatus_Null != m_mouseMoveStatus + || !rcWnd.contains(mapFromGlobal(QCursor::pos()))) + { + setCursor(Qt::ArrowCursor); + } + else + { + HGImageInfo info; + HGBase_GetImageInfo(m_image, &info); + + int xShow = mapFromGlobal(QCursor::pos()).x() - m_showRect.left; + int yShow = mapFromGlobal(QCursor::pos()).y() - m_showRect.top; + int xImg = xShow * (int)info.width / (m_showRect.right - m_showRect.left); + int yImg = yShow * (int)info.height / (m_showRect.bottom - m_showRect.top); + + if (xImg >= 0 && xImg < (int)info.width && yImg >= 0 && yImg < (int)info.height) + { + setCursor(Qt::CrossCursor); + } + else + { + setCursor(Qt::ArrowCursor); + } + } + } +} + +HGImgView::MouseStatus HGImgView::getMouseStatus(const QPoint &pt) +{ + MouseStatus mouseStatus = MouseStatus_Null; + if (MouseStatus_Null != m_mousePressStatus || 0 != m_operate || m_draging) + { + return mouseStatus; + } + + if (!m_mouseOn) + { + return mouseStatus; + } + + if (m_hScroll && m_vScroll) + { + if (getHScrollSliderPos().contains(pt)) + mouseStatus = MouseStatus_HScrollSlider; + else if (getHScrollLeftPos().contains(pt)) + mouseStatus = MouseStatus_HScrollLeft; + else if (getHScrollRightPos().contains(pt)) + mouseStatus = MouseStatus_HScrollRight; + else if (getHScrollPos().contains(pt)) + mouseStatus = MouseStatus_HScroll; + else if (getVScrollSliderPos().contains(pt)) + mouseStatus = MouseStatus_VScrollSlider; + else if (getVScrollTopPos().contains(pt)) + mouseStatus = MouseStatus_VScrollTop; + else if (getVScrollBottomPos().contains(pt)) + mouseStatus = MouseStatus_VScrollBottom; + else if (getVScrollPos().contains(pt)) + mouseStatus = MouseStatus_VScroll; + else if (getNullScrollPos().contains(pt)) + mouseStatus = MouseStatus_NullScroll; + } + else if (m_hScroll && !m_vScroll) + { + if (getHScrollSliderPos().contains(pt)) + mouseStatus = MouseStatus_HScrollSlider; + else if (getHScrollLeftPos().contains(pt)) + mouseStatus = MouseStatus_HScrollLeft; + else if (getHScrollRightPos().contains(pt)) + mouseStatus = MouseStatus_HScrollRight; + else if (getHScrollPos().contains(pt)) + mouseStatus = MouseStatus_HScroll; + } + else if (!m_hScroll && m_vScroll) + { + if (getVScrollSliderPos().contains(pt)) + mouseStatus = MouseStatus_VScrollSlider; + else if (getVScrollTopPos().contains(pt)) + mouseStatus = MouseStatus_VScrollTop; + else if (getVScrollBottomPos().contains(pt)) + mouseStatus = MouseStatus_VScrollBottom; + else if (getVScrollPos().contains(pt)) + mouseStatus = MouseStatus_VScroll; + } + + return mouseStatus; +} + +QRect HGImgView::getHScrollLeftPos() +{ + assert(m_hScroll); + + return QRect(0, this->height() - m_scrollSize, m_scrollSize, m_scrollSize); +} + +QRect HGImgView::getHScrollRightPos() +{ + assert(m_hScroll); + + if (!m_vScroll) + { + return QRect(this->width() - m_scrollSize, this->height() - m_scrollSize, m_scrollSize, m_scrollSize); + } + + return QRect(this->width() - 2 * m_scrollSize, this->height() - m_scrollSize, m_scrollSize, m_scrollSize); +} + +QRect HGImgView::getHScrollPos() +{ + assert(m_hScroll); + + if (!m_vScroll) + { + return QRect(0, this->height() - m_scrollSize, this->width(), m_scrollSize); + } + + return QRect(0, this->height() - m_scrollSize, this->width() - m_scrollSize, m_scrollSize); +} + +QRect HGImgView::getHScrollSliderPos() +{ + assert(m_hScroll); + + QRect rect; + rect.setY(this->height() - m_scrollSize); + rect.setHeight(m_scrollSize); + if (!m_vScroll) + { + int rollTotalLen = this->width() - 2 * m_scrollSize; + int rollLeft = round((double)rollTotalLen * (-m_showRect.left) / (double)(m_showRect.right - m_showRect.left)); + int rollRight = round((double)rollTotalLen * (-m_showRect.left + this->width()) / (double)(m_showRect.right - m_showRect.left)); + int rollLen = rollRight - rollLeft; + if (rollLen < m_minScrollSliderSize) + { + rollLen = m_minScrollSliderSize; + rollLeft = round((double)(rollTotalLen - m_minScrollSliderSize) * (-m_showRect.left) / (double)(m_showRect.right - m_showRect.left - this->width())); + } + + rect.setX(rollLeft + m_scrollSize); + rect.setWidth(rollLen); + } + else + { + int rollTotalLen = this->width() - 3 * m_scrollSize; + int rollLeft = round((double)rollTotalLen * (-m_showRect.left) / (double)(m_showRect.right - m_showRect.left)); + int rollRight = round((double)rollTotalLen * (-m_showRect.left + this->width() - m_scrollSize) / (double)(m_showRect.right - m_showRect.left)); + int rollLen = rollRight - rollLeft; + if (rollLen < m_minScrollSliderSize) + { + rollLen = m_minScrollSliderSize; + rollLeft = round((double)(rollTotalLen - m_minScrollSliderSize) * (-m_showRect.left) / (double)(m_showRect.right - m_showRect.left - this->width() + m_scrollSize)); + } + + rect.setX(rollLeft + m_scrollSize); + rect.setWidth(rollLen); + } + + return rect; +} + +QRect HGImgView::getVScrollTopPos() +{ + assert(m_vScroll); + + return QRect(this->width() - m_scrollSize, 0, m_scrollSize, m_scrollSize); +} + +QRect HGImgView::getVScrollBottomPos() +{ + assert(m_vScroll); + + if (!m_hScroll) + { + return QRect(this->width() - m_scrollSize, this->height() - m_scrollSize, m_scrollSize, m_scrollSize); + } + + return QRect(this->width() - m_scrollSize, this->height() - 2 * m_scrollSize, m_scrollSize, m_scrollSize); +} + +QRect HGImgView::getVScrollPos() +{ + assert(m_vScroll); + + if (!m_hScroll) + { + return QRect(this->width() - m_scrollSize, 0, m_scrollSize, this->height()); + } + + return QRect(this->width() - m_scrollSize, 0, m_scrollSize, this->height() - m_scrollSize); +} + +QRect HGImgView::getVScrollSliderPos() +{ + assert(m_vScroll); + + QRect rect; + rect.setX(this->width() - m_scrollSize); + rect.setWidth(m_scrollSize); + if (!m_hScroll) + { + int rollTotalLen = this->height() - 2 * m_scrollSize; + int rollTop = round((double)rollTotalLen * (-m_showRect.top) / (double)(m_showRect.bottom - m_showRect.top)); + int rollBottom = round((double)rollTotalLen * (-m_showRect.top + this->height()) / (double)(m_showRect.bottom - m_showRect.top)); + int rollLen = rollBottom - rollTop; + if (rollLen < m_minScrollSliderSize) + { + rollLen = m_minScrollSliderSize; + rollTop = round((double)(rollTotalLen - m_minScrollSliderSize) * (-m_showRect.top) / (double)(m_showRect.bottom - m_showRect.top - this->height())); + } + + rect.setY(rollTop + m_scrollSize); + rect.setHeight(rollLen); + } + else + { + int rollTotalLen = this->height() - 3 * m_scrollSize; + int rollTop = round((double)rollTotalLen * (-m_showRect.top) / (double)(m_showRect.bottom - m_showRect.top)); + int rollBottom = round((double)rollTotalLen * (-m_showRect.top + this->height() - m_scrollSize) / (double)(m_showRect.bottom - m_showRect.top)); + int rollLen = rollBottom - rollTop; + if (rollLen < m_minScrollSliderSize) + { + rollLen = m_minScrollSliderSize; + rollTop = round((double)(rollTotalLen - m_minScrollSliderSize) * (-m_showRect.top) / (double)(m_showRect.bottom - m_showRect.top - this->height() + m_scrollSize)); + } + + rect.setY(rollTop + m_scrollSize); + rect.setHeight(rollLen); + } + + return rect; +} + +QRect HGImgView::getNullScrollPos() +{ + assert(m_hScroll && m_vScroll); + return QRect(this->width() - m_scrollSize, this->height() - m_scrollSize, m_scrollSize, m_scrollSize); +} + +void HGImgView::Show() +{ + repaint(); +} diff --git a/app/HGProductionTool/HGImgView.h b/app/HGProductionTool/HGImgView.h new file mode 100644 index 0000000..73f9581 --- /dev/null +++ b/app/HGProductionTool/HGImgView.h @@ -0,0 +1,146 @@ +#ifndef __HGIMGVIEW_H__ +#define __HGIMGVIEW_H__ + +#include "base/HGDef.h" +#include "base/HGBaseErr.h" +#include "base/HGImage.h" +#include + +class HGImgView : public QWidget +{ + Q_OBJECT +public: + HGImgView(QWidget* parent = nullptr); + virtual ~HGImgView(); + + HGResult setScrollSize(int size); + HGResult setMinScrollSliderSize(int size); + HGResult setHScrollLeftImage(const QImage *normalImage, const QImage *hotImage, const QImage *pushImage); + HGResult setHScrollRightImage(const QImage *normalImage, const QImage *hotImage, const QImage *pushImage); + HGResult setVScrollTopImage(const QImage *normalImage, const QImage *hotImage, const QImage *pushImage); + HGResult setVScrollBottomImage(const QImage *normalImage, const QImage *hotImage, const QImage *pushImage); + HGResult setHScrollImage(const QImage *image, const HGRect *stretch); + HGResult setHScrollSliderImage(const QImage *normalImage, const HGRect *normalStretch, const QImage *hotImage, const HGRect *hotStretch, + const QImage *pushImage, const HGRect *pushStretch); + HGResult setVScrollImage(const QImage *image, const HGRect *stretch); + HGResult setVScrollSliderImage(const QImage *normalImage, const HGRect *normalStretch, const QImage *hotImage, const HGRect *hotStretch, + const QImage *pushImage, const HGRect *pushStretch); + HGResult setNullScrollImage(const QImage *image); + + HGResult enableScroll(bool enable); + HGResult addImage(HGImage image); + HGResult clearImage(); + HGResult getImage(HGImage *image); + + HGResult rotateLeft(); + HGResult rotateRight(); + HGResult rotate180(); + + HGResult zoomIn(const HGPoint *pCenter); + HGResult zoomOut(const HGPoint *pCenter); + HGResult realSize(); + HGResult fitWndSize(); + HGResult fitWndWidth(); + + HGResult showColorInfo(bool show); + +signals: + void escape(); + void doubleClicked(); + void mousePos(int x, int y); + void scaleChanged(double scale); + void drop(const QObject *source, const QStringList &fileNames); + +private: + + enum MouseStatus + { + MouseStatus_Null = 0, + MouseStatus_HScroll, + MouseStatus_HScrollSlider, + MouseStatus_HScrollLeft, + MouseStatus_HScrollRight, + MouseStatus_VScroll, + MouseStatus_VScrollSlider, + MouseStatus_VScrollTop, + MouseStatus_VScrollBottom, + MouseStatus_NullScroll + }; + +protected: + virtual void mousePressEvent(QMouseEvent *e); + virtual void mouseMoveEvent(QMouseEvent* e); + virtual void mouseReleaseEvent(QMouseEvent *e); + virtual void enterEvent(QEvent *e); + virtual void leaveEvent(QEvent *e); + virtual void paintEvent(QPaintEvent* e); + virtual void wheelEvent(QWheelEvent* e); + virtual void resizeEvent(QResizeEvent* e); + virtual void keyPressEvent(QKeyEvent *e); + virtual void dragEnterEvent(QDragEnterEvent *e); + virtual void dragMoveEvent(QDragMoveEvent *e); + virtual void dragLeaveEvent(QDragLeaveEvent *e); + virtual void dropEvent(QDropEvent *e); + virtual void mouseDoubleClickEvent(QMouseEvent* e); + +private: + static void GetMinShowImageRect(const HGRect *pWnd, int nImgWidth, int nImgHeight, bool &bShowImage, HGRectF &rcShowImage); + static void ResizeShowImageRect(bool &bShowImage, HGRectF &rcShowImage, float fNewWidth, float fNewHeight, const HGPoint *pCenter); + static void recalcShowRect(int wndWidth, int wndHeight, int scrollSize, bool hScroll, bool vScroll, bool showImage, HGRectF &imageRect); + static void DrawImage(QPainter &painter, const QRect &destRect, const QImage *image, const QRect &stretchRect); + + QImage* createQImage(); + void DrawScroll(QPainter &painter); + void reset(); + void updateMoveStatusAndCursor(); + MouseStatus getMouseStatus(const QPoint &pt); + + QRect getHScrollLeftPos(); + QRect getHScrollRightPos(); + QRect getHScrollPos(); + QRect getHScrollSliderPos(); + QRect getVScrollTopPos(); + QRect getVScrollBottomPos(); + QRect getVScrollPos(); + QRect getVScrollSliderPos(); + QRect getNullScrollPos(); + + void Show(); + +private: + int m_scrollSize; + int m_minScrollSliderSize; + QImage *m_hScrollLeftImage[3]; + QImage *m_hScrollRightImage[3]; + QImage *m_vScrollTopImage[3]; + QImage *m_vScrollBottomImage[3]; + QImage *m_hScrollImage; + QRect m_hScrollImageStretch; + QImage *m_hScrollSliderImage[3]; + QRect m_hScrollSliderImageStretch[3]; + QImage *m_vScrollImage; + QRect m_vScrollImageStretch; + QImage *m_vScrollSliderImage[3]; + QRect m_vScrollSliderImageStretch[3]; + QImage *m_nullScrollImage; + + bool m_enableScroll; + bool m_mouseOn; + bool m_hScroll; + bool m_vScroll; + HGImage m_image; + QImage *m_qImage; + bool m_showImage; + HGRectF m_showRect; + MouseStatus m_mouseMoveStatus; + MouseStatus m_mousePressStatus; + int m_mousePressBeginX; + int m_mousePressBeginY; + bool m_showColorInfo; + int m_operate; + int m_beginX; + int m_beginY; + bool m_draging; +}; + +#endif /* __HGIMGVIEW_HPP__ */ diff --git a/app/HGProductionTool/HGProductionTool.pro b/app/HGProductionTool/HGProductionTool.pro new file mode 100644 index 0000000..f580890 --- /dev/null +++ b/app/HGProductionTool/HGProductionTool.pro @@ -0,0 +1,94 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +TARGET = ProductionTool + +RC_ICONS = image_rsc/logo/logo.ico + +win32 { + DEFINES += _CRT_SECURE_NO_WARNINGS + + contains(QT_ARCH, i386) { + LIBS += -L../sdk/lib/x86/Release -lHGBase -lHGImgFmt -lHGImgProc -lsane + LIBS += -L../../db/Debug -lHGPdtToolDb + CONFIG(release, debug|release) { + DESTDIR = ../release/x86/ + } + CONFIG(debug, debug|release) { + + } + } + contains(QT_ARCH, x86_64){ + LIBS += -L../sdk/lib/x64/Release -lHGBase -lHGImgFmt -lHGImgProc -lsane + LIBS += -L../../db/Debug -lHGPdtToolDb + CONFIG(release, debug|release) { + DESTDIR = ../release/x64/ + } + CONFIG(debug, debug|release) { + + } + } +} + +INCLUDEPATH += $$PWD/../utility/ +INCLUDEPATH += $$PWD/../modules/ +INCLUDEPATH += $$PWD/../sdk/include/ +INCLUDEPATH += $$PWD/../../db/HGPdtToolDb/ + +SOURCES += \ + HGImgView.cpp \ + HGUIGlobal.cpp \ + analysisjson.cpp \ + dialog_accountmanage.cpp \ + dialog_changepwd.cpp \ + dialog_login.cpp \ + dialog_rootfuntion.cpp \ + form_maininterface.cpp \ + form_texttips.cpp \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + HGImgView.h \ + HGUIGlobal.h \ + analysisjson.h \ + dialog_accountmanage.h \ + dialog_changepwd.h \ + dialog_login.h \ + dialog_rootfuntion.h \ + form_maininterface.h \ + form_texttips.h \ + mainwindow.h + +FORMS += \ + dialog_accountmanage.ui \ + dialog_changepwd.ui \ + dialog_login.ui \ + dialog_rootfuntion.ui \ + form_maininterface.ui \ + form_texttips.ui \ + mainwindow.ui + +RESOURCES += \ + ProductionTool_resource.qrc + +TRANSLATIONS += \ + ProductionTool_zh_CN.ts \ + +DISTFILES += \ + ProductionTool_zh_CN.qm \ \ + ProductionTool_zh_CN.ts diff --git a/app/HGProductionTool/HGUIGlobal.cpp b/app/HGProductionTool/HGUIGlobal.cpp new file mode 100644 index 0000000..fd3dbbf --- /dev/null +++ b/app/HGProductionTool/HGUIGlobal.cpp @@ -0,0 +1,20 @@ +#include "HGUIGlobal.h" +#include "base/HGDef.h" +#include "base/HGInc.h" +#include "base/HGUtility.h" + +QString getStdFileName(const QString &fileName) +{ + char result[512] = {0}; + HGBase_StandardiseFileName(fileName.toStdString().c_str(), result, 512); + return result; +} + +std::string getStdString(const QString &str) +{ +#ifdef HG_CMP_MSC + return str.toLocal8Bit().data(); +#else + return str.toStdString(); +#endif +} diff --git a/app/HGProductionTool/HGUIGlobal.h b/app/HGProductionTool/HGUIGlobal.h new file mode 100644 index 0000000..d1da4d1 --- /dev/null +++ b/app/HGProductionTool/HGUIGlobal.h @@ -0,0 +1,10 @@ +#ifndef __HGUIGLOBAL_H__ +#define __HGUIGLOBAL_H__ + +#include + +QString getStdFileName(const QString &fileName); + +std::string getStdString(const QString &str); + +#endif /* __HGUIGLOBAL_H__ */ diff --git a/app/HGProductionTool/ProductionTool_resource.qrc b/app/HGProductionTool/ProductionTool_resource.qrc new file mode 100644 index 0000000..a234ee7 --- /dev/null +++ b/app/HGProductionTool/ProductionTool_resource.qrc @@ -0,0 +1,11 @@ + + + image_rsc/icon/close.ico + image_rsc/icon/minum.ico + image_rsc/icon/setting.ico + image_rsc/logo/logo.ico + + + ProductionTool_zh_CN.qm + + diff --git a/app/HGProductionTool/ProductionTool_zh_CN.qm b/app/HGProductionTool/ProductionTool_zh_CN.qm new file mode 100644 index 0000000..67fef8e Binary files /dev/null and b/app/HGProductionTool/ProductionTool_zh_CN.qm differ diff --git a/app/HGProductionTool/ProductionTool_zh_CN.ts b/app/HGProductionTool/ProductionTool_zh_CN.ts new file mode 100644 index 0000000..078a09c --- /dev/null +++ b/app/HGProductionTool/ProductionTool_zh_CN.ts @@ -0,0 +1,405 @@ + + + + + Dialog_accountManage + + + Dialog + 账户管理 + + + + Account List: + 账户列表: + + + + NEW + 新建账户 + + + + Destroy + 销毁账户 + + + + Set Password + 重置密码 + + + + + + + tips + 提示 + + + + create user failed: + 创建账户失败: + + + + Question + 询问 + + + + Are you sure to destroy: + 请确认是否删除账户: + + + + yes + 确定 + + + + no + 取消 + + + + destroy user failed: + 销毁账户失败: + + + + change password succeed + 修改密码成功 + + + + change password failed: + 修改密码失败: + + + + Dialog_changePwd + + + Dialog + 修改密码 + + + + old password: + 旧密码: + + + + new password: + 新密码: + + + + confirm new password: + 确认密码: + + + + OK + 确定 + + + + Cancel + 取消 + + + + + tips + 提示 + + + + The passwords entered twice are inconsistent + 两次输入的密码不一致 + + + + Change passwords failed: + 修改密码失败: + + + + Dialog_logIn + + + Dialog + 登录 + + + + TextLabel + + + + + account: + 账户: + + + + password: + 密码: + + + + host: + IP地址: + + + + port: + 端口号: + + + + LOG IN + 登录 + + + + EXIT + 退出 + + + + Set host and port + 设置IP与端口 + + + + Minimize + 最小化 + + + + Close + 关闭 + + + + LogIn + 登录 + + + + tips + 提示 + + + + Login failed: + 登录失败: + + + + Dialog_rootFuntion + + + Dialog + + + + + Account: + 账户: + + + + password: + 密码: + + + + OK + 确定 + + + + Cancel + 取消 + + + + Create account + 创建账户 + + + + Reset password + 重置密码 + + + + new password: + 新密码: + + + + Form_mainInterface + + + Form + + + + + SN: + + + + + Privious Step + 上一步 + + + + PASS + 通过 + + + + FAIL + 失败 + + + + STOP + 终止 + + + + Next Step + 下一步 + + + + 1.Dial switch verification + + + + + 2.Check the function of ship type switch + + + + + 3.Testing + + + + + Form_textTips + + + Form + + + + + + Please complete the calibration of ship type switch + + + + + Please power on the device and observe the startup status + + + + + Testing........ + + + + + MainWindow + + + MainWindow + + + + + menu_device + 设备 + + + + menu_user + 用户 + + + + act_newDevice + 新建项目 + + + + act_manage + 账户管理 + + + + act_changePwd + 修改密码 + + + + act_export + 导出 + + + + act_logOut + 登出 + + + + act_close + 关闭 + + + + tips + 提示 + + + + cannot create more table + 不能创建更多项目 + + + + Illegal user + 非法的用户 + + + + Wrong password + 密码错误 + + + + Database error + 数据库错误 + + + + connect error + 连接错误 + + + + Failed + 错误 + + + diff --git a/app/HGProductionTool/analysisjson.cpp b/app/HGProductionTool/analysisjson.cpp new file mode 100644 index 0000000..9c8411a --- /dev/null +++ b/app/HGProductionTool/analysisjson.cpp @@ -0,0 +1,98 @@ +#include "analysisjson.h" +#include +#include +#include +#include +#include + +AnalysisJson::AnalysisJson(QString path) +{ + if(QFile::exists(path)){ + QFile file(path); + if(file.open(QIODevice::OpenModeFlag::ReadOnly)) + { + m_json = QJsonDocument::fromJson(file.readAll()); + file.close(); + } + } +} + +std::vector AnalysisJson::GetNode() +{ + std::vector nodes; + if(!m_json.isObject()) + return nodes; + auto obj = m_json.object(); + for(auto key : obj.keys()) + { + if(key != "global") + nodes.push_back(json_node{obj[key].toObject()["title"].toString(), + obj[key].toObject()["name"].toString(), + obj[key].toObject()["man"].toBool(), + obj[key].toObject()["err-level"].toInt()}); + } + return nodes; +} + +AnalysisJson::json_global AnalysisJson::GetGlobal() +{ + if(!m_json.isObject()) + return json_global(); + auto obj = m_json.object()["global"].toObject(); + return json_global{obj["vid-org"].toInt(), + obj["pid-org"].toInt(), + obj["vid-to"].toInt(), + obj["pid-to"].toInt()}; + +} + +bool AnalysisJson::savejson(QString path, std::vector json) +{ + + QFileInfo info(path); + if(!info.isFile()) + return false; + if(!info.dir().exists()) + QDir().mkdir(info.dir().path()); + QJsonDocument doc; + QJsonObject obj; + int index =1; + for(auto json_ : json) + { + QJsonObject tmp_obj; + tmp_obj["title"] = json_.title; + tmp_obj["name"] = json_.name; + tmp_obj["man"] = json_.is_man; + tmp_obj["err_level"] = json_.err_level; + obj[QString::number(index++)] = tmp_obj; + } + doc.setObject(obj); + QFile file(path); + if(file.open(QIODevice::OpenModeFlag::WriteOnly)) + { + file.write(doc.toJson()); + file.close(); + return true; + } + return false; +} + +bool AnalysisJson::savejson(QString path, QJsonDocument doc) +{ + QFileInfo info(path); + if(!info.isFile()) + return false; + if(!info.dir().exists()) + QDir().mkdir(info.dir().path()); + QFile file(path); + if(file.open(QIODevice::OpenModeFlag::WriteOnly)) + { + file.write(doc.toJson()); + file.close(); + return true; + } + return false; +} + + + diff --git a/app/HGProductionTool/analysisjson.h b/app/HGProductionTool/analysisjson.h new file mode 100644 index 0000000..a18adc5 --- /dev/null +++ b/app/HGProductionTool/analysisjson.h @@ -0,0 +1,35 @@ +#ifndef ANALYSISJSON_H +#define ANALYSISJSON_H +#include +#include +#include + +class AnalysisJson +{ +public: + struct json_node{ + QString title; + QString name; + bool is_man; + std::int32_t err_level; + }; + + struct json_global{ + std::int32_t vid_org; + std::int32_t pid_org; + std::int32_t vid_to; + std::int32_t pid_to; + }; + + AnalysisJson() = delete ; + AnalysisJson(QString path); + std::vector GetNode(); + json_global GetGlobal(); + bool savejson(QString path,std::vector json); + bool savejson(QString path, QJsonDocument doc); + +private: + QJsonDocument m_json; +}; + +#endif // ANALYSISJSON_H diff --git a/app/HGProductionTool/dialog_accountmanage.cpp b/app/HGProductionTool/dialog_accountmanage.cpp new file mode 100644 index 0000000..b8d7227 --- /dev/null +++ b/app/HGProductionTool/dialog_accountmanage.cpp @@ -0,0 +1,113 @@ +#include "dialog_accountmanage.h" +#include "ui_dialog_accountmanage.h" +#include "dialog_rootfuntion.h" +#include "mainwindow.h" +#include + + +Dialog_accountManage::Dialog_accountManage(HGPdtToolDbUserMgr pdtToolDbuserMgr, QWidget *parent) : + QDialog(parent), + m_pdtToolDbuserMgr(pdtToolDbuserMgr), + ui(new Ui::Dialog_accountManage) +{ + ui->setupUi(this); + + setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); + + HGChar* userNameList[100]; + HGUInt count = 0; + HGPdtToolDb_GetUserList(pdtToolDbuserMgr, userNameList, 100, &count); + + for (int i = 0; i < count; ++i) + { + ui->listWidget->addItem(QString(userNameList[i])); + } + + ui->listWidget->setCurrentRow(0); + + HGPdtToolDb_ReleaseUserList(userNameList, count); +} + +Dialog_accountManage::~Dialog_accountManage() +{ + delete ui; +} + +void Dialog_accountManage::on_pbtn_newAccount_clicked() +{ + Dialog_rootFuntion dlg(false, this); + if (dlg.exec()) + { + HGResult ret = HGPdtToolDb_CreateUser(m_pdtToolDbuserMgr, dlg.getAccount().toStdString().c_str(), dlg.getPassword().toStdString().c_str()); + if (ret == HGBASE_ERR_OK) + { + ui->listWidget->addItem(dlg.getAccount()); + } + else + { + QMessageBox::information(this, tr("tips"), tr("create user failed: ") + MainWindow::getLogInfo(ret)); + } + } +} + +void Dialog_accountManage::on_pbtn_destroyAccount_clicked() +{ + QString userName = ui->listWidget->currentItem()->text(); + + QMessageBox msg(QMessageBox::Question, tr("Question"), + tr("Are you sure to destroy: ") + userName, + QMessageBox::Yes | QMessageBox::No, this); + msg.setButtonText(QMessageBox::Yes, tr("yes")); + msg.setButtonText(QMessageBox::No, tr("no")); + msg.exec(); + if (msg.clickedButton() == msg.button(QMessageBox::Yes)) + { + HGResult ret = HGPdtToolDb_DestroyUser(m_pdtToolDbuserMgr, userName.toStdString().c_str()); + if(ret == HGBASE_ERR_OK) + { + ui->listWidget->takeItem(ui->listWidget->currentRow()); + } + else + { + QMessageBox::information(this, tr("tips"), tr("destroy user failed: ") + MainWindow::getLogInfo(ret)); + } + } + else + { + return; + } +} + +void Dialog_accountManage::on_pbtn_changePwd_clicked() +{ + Dialog_rootFuntion dlg(true, this); + if (dlg.exec()) + { + QString userName = ui->listWidget->currentItem()->text(); + HGResult ret = HGPdtToolDb_SetPassword(m_pdtToolDbuserMgr, userName.toStdString().c_str(), dlg.getPassword().toStdString().c_str()); + if(ret == HGBASE_ERR_OK) + { + QMessageBox::information(this, tr("tips"), tr("change password succeed")); + } + else + { + QMessageBox::information(this, tr("tips"), tr("change password failed: ") + MainWindow::getLogInfo(ret)); + } + } +} + +void Dialog_accountManage::on_pbtn_exit_clicked() +{ + close(); +} + +void Dialog_accountManage::on_listWidget_itemDoubleClicked(QListWidgetItem *item) +{ + (void)item; + on_pbtn_changePwd_clicked(); +} + + + + + diff --git a/app/HGProductionTool/dialog_accountmanage.h b/app/HGProductionTool/dialog_accountmanage.h new file mode 100644 index 0000000..f621f4e --- /dev/null +++ b/app/HGProductionTool/dialog_accountmanage.h @@ -0,0 +1,37 @@ +#ifndef DIALOG_ACCOUNTMANAGE_H +#define DIALOG_ACCOUNTMANAGE_H + +#include +#include "HGPdtToolDb.h" +#include + +namespace Ui { +class Dialog_accountManage; +} + +class Dialog_accountManage : public QDialog +{ + Q_OBJECT + +public: + explicit Dialog_accountManage(HGPdtToolDbUserMgr pdtToolDbuserMgr, QWidget *parent = nullptr); + ~Dialog_accountManage(); + +private slots: + void on_pbtn_newAccount_clicked(); + + void on_pbtn_destroyAccount_clicked(); + + void on_pbtn_changePwd_clicked(); + + void on_pbtn_exit_clicked(); + + void on_listWidget_itemDoubleClicked(QListWidgetItem *item); + +private: + Ui::Dialog_accountManage *ui; + + HGPdtToolDbUserMgr m_pdtToolDbuserMgr; +}; + +#endif // DIALOG_ACCOUNTMANAGE_H diff --git a/app/HGProductionTool/dialog_accountmanage.ui b/app/HGProductionTool/dialog_accountmanage.ui new file mode 100644 index 0000000..31bac7b --- /dev/null +++ b/app/HGProductionTool/dialog_accountmanage.ui @@ -0,0 +1,99 @@ + + + Dialog_accountManage + + + + 0 + 0 + 425 + 209 + + + + Dialog + + + + + + + + Account List: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + NEW + + + + + + + Destroy + + + + + + + Set Password + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/app/HGProductionTool/dialog_changepwd.cpp b/app/HGProductionTool/dialog_changepwd.cpp new file mode 100644 index 0000000..0ea9e3c --- /dev/null +++ b/app/HGProductionTool/dialog_changepwd.cpp @@ -0,0 +1,49 @@ +#include "dialog_changepwd.h" +#include "ui_dialog_changepwd.h" +#include +#include "mainwindow.h" + +Dialog_changePwd::Dialog_changePwd(HGPdtToolDbUserMgr pdtToolDbuserMgr, QWidget *parent) : + QDialog(parent), + m_pdtToolDbuserMgr(pdtToolDbuserMgr), + ui(new Ui::Dialog_changePwd) +{ + ui->setupUi(this); + + setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); + + ui->lineEdit_oldPwd->setEchoMode(QLineEdit::EchoMode::Password); + ui->lineEdit_newPwd->setEchoMode(QLineEdit::EchoMode::Password); + ui->lineEdit_confirmNewPwd->setEchoMode(QLineEdit::EchoMode::Password); +} + +Dialog_changePwd::~Dialog_changePwd() +{ + delete ui; +} + +void Dialog_changePwd::on_pbtn_ok_clicked() +{ + QString oldPwd = ui->lineEdit_oldPwd->text(); + QString newPwd = ui->lineEdit_newPwd->text(); + QString confirmNewPwd = ui->lineEdit_confirmNewPwd->text(); + + if(newPwd != confirmNewPwd) + { + QMessageBox::information(this, tr("tips"), tr("The passwords entered twice are inconsistent")); + return; + } + + HGResult ret = HGPdtToolDb_ModifyPassword(m_pdtToolDbuserMgr, oldPwd.toStdString().c_str(), newPwd.toStdString().c_str()); + if(ret != HGBASE_ERR_OK) + { + QMessageBox::information(this, tr("tips"), tr("Change passwords failed: ") + MainWindow::getLogInfo(ret)); + return; + } + accept(); +} + +void Dialog_changePwd::on_pbtn_cancel_clicked() +{ + reject(); +} diff --git a/app/HGProductionTool/dialog_changepwd.h b/app/HGProductionTool/dialog_changepwd.h new file mode 100644 index 0000000..4a12330 --- /dev/null +++ b/app/HGProductionTool/dialog_changepwd.h @@ -0,0 +1,31 @@ +#ifndef DIALOG_CHANGEPWD_H +#define DIALOG_CHANGEPWD_H + +#include +#include "HGPdtToolDb.h" + +namespace Ui { +class Dialog_changePwd; +} + +class Dialog_changePwd : public QDialog +{ + Q_OBJECT + +public: + explicit Dialog_changePwd(HGPdtToolDbUserMgr pdtToolDbuserMgr, QWidget *parent = nullptr); + ~Dialog_changePwd(); + +private slots: + void on_pbtn_ok_clicked(); + + void on_pbtn_cancel_clicked(); + +private: + Ui::Dialog_changePwd *ui; + + HGPdtToolDbUserMgr m_pdtToolDbuserMgr; + +}; + +#endif // DIALOG_CHANGEPWD_H diff --git a/app/HGProductionTool/dialog_changepwd.ui b/app/HGProductionTool/dialog_changepwd.ui new file mode 100644 index 0000000..242c6df --- /dev/null +++ b/app/HGProductionTool/dialog_changepwd.ui @@ -0,0 +1,172 @@ + + + Dialog_changePwd + + + + 0 + 0 + 389 + 150 + + + + Dialog + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + old password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + new password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + confirm new password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + diff --git a/app/HGProductionTool/dialog_login.cpp b/app/HGProductionTool/dialog_login.cpp new file mode 100644 index 0000000..127a902 --- /dev/null +++ b/app/HGProductionTool/dialog_login.cpp @@ -0,0 +1,114 @@ +#include "dialog_login.h" +#include "ui_dialog_login.h" +#include +#include "mainwindow.h" + +Dialog_logIn::Dialog_logIn(QWidget *parent) : + QDialog(parent), + m_pdtToolDbuserMgr(nullptr), + ui(new Ui::Dialog_logIn) +{ + ui->setupUi(this); + + setWindowFlags(Qt::FramelessWindowHint); + + ui->pbtn_setting->setToolTip(tr("Set host and port")); + ui->pbtn_minum->setToolTip(tr("Minimize")); + ui->pbtn_close->setToolTip(tr("Close")); + + ui->label_title->setText(tr("LogIn")); + + ui->lineEdit_account->setText("root"); + ui->lineEdit_password->setEchoMode(QLineEdit::EchoMode::Password); + ui->lineEdit_host->setText("192.168.1.70"); + ui->lineEdit_port->setText("3306"); + + ui->label_host->setVisible(false); + ui->label_port->setVisible(false); + ui->lineEdit_host->setVisible(false); + ui->lineEdit_port->setVisible(false); +} + +Dialog_logIn::~Dialog_logIn() +{ + delete ui; +} + +HGPdtToolDbUserMgr Dialog_logIn::GetUserMgr() +{ + return m_pdtToolDbuserMgr; +} + +void Dialog_logIn::mousePressEvent(QMouseEvent *event) +{ + if(event->button()==Qt::LeftButton) + { + m_leftMousePressed = true; + m_startPos = event->globalPos(); + } +} + +void Dialog_logIn::mouseMoveEvent(QMouseEvent *event) +{ + if(m_leftMousePressed) + { + this->window()->move(this->window()->geometry().topLeft() + event->globalPos() - m_startPos); + m_startPos = event->globalPos(); + } +} + +void Dialog_logIn::mouseReleaseEvent(QMouseEvent *event) +{ + if(event->button()==Qt::LeftButton) + { + m_leftMousePressed = false; + } +} + +void Dialog_logIn::on_pbtn_login_clicked() +{ + QString account = ui->lineEdit_account->text(); + QString password = ui->lineEdit_password->text(); + QString host = ui->lineEdit_host->text(); + QString port = ui->lineEdit_port->text(); + + HGResult ret = HGPdtToolDb_CreateUserMgr(host.toStdString().c_str(), port.toInt(), + account.toStdString().c_str(), password.toStdString().c_str(), &m_pdtToolDbuserMgr); + if (NULL != m_pdtToolDbuserMgr) + { + accept(); + } + else + { + QMessageBox::information(this, tr("tips"), tr("Login failed: ") + MainWindow::getLogInfo(ret)); + return; + } +} + +void Dialog_logIn::on_pushButton_exit_clicked() +{ + reject(); +} + +void Dialog_logIn::on_pbtn_setting_clicked(bool checked) +{ + ui->label_user->setVisible(!checked); + ui->label_password->setVisible(!checked); + ui->lineEdit_account->setVisible(!checked); + ui->lineEdit_password->setVisible(!checked); + + ui->label_host->setVisible(checked); + ui->label_port->setVisible(checked); + ui->lineEdit_host->setVisible(checked); + ui->lineEdit_port->setVisible(checked); +} + +void Dialog_logIn::on_pbtn_minum_clicked() +{ + this->window()->showMinimized(); +} + +void Dialog_logIn::on_pbtn_close_clicked() +{ + close(); +} diff --git a/app/HGProductionTool/dialog_login.h b/app/HGProductionTool/dialog_login.h new file mode 100644 index 0000000..84cddb2 --- /dev/null +++ b/app/HGProductionTool/dialog_login.h @@ -0,0 +1,45 @@ +#ifndef DIALOG_LOGIN_H +#define DIALOG_LOGIN_H + +#include +#include "HGPdtToolDb.h" + +namespace Ui { +class Dialog_logIn; +} + +class Dialog_logIn : public QDialog +{ + Q_OBJECT + +public: + explicit Dialog_logIn(QWidget *parent = nullptr); + ~Dialog_logIn(); + + HGPdtToolDbUserMgr GetUserMgr(); + + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + +private slots: + void on_pbtn_login_clicked(); + + void on_pushButton_exit_clicked(); + + void on_pbtn_setting_clicked(bool checked); + + void on_pbtn_minum_clicked(); + + void on_pbtn_close_clicked(); + +private: + Ui::Dialog_logIn *ui; + + HGPdtToolDbUserMgr m_pdtToolDbuserMgr; + QPoint m_startPos; + QPoint m_endPos; + bool m_leftMousePressed; +}; + +#endif // DIALOG_LOGIN_H diff --git a/app/HGProductionTool/dialog_login.ui b/app/HGProductionTool/dialog_login.ui new file mode 100644 index 0000000..65d7249 --- /dev/null +++ b/app/HGProductionTool/dialog_login.ui @@ -0,0 +1,366 @@ + + + Dialog_logIn + + + + 0 + 0 + 434 + 245 + + + + Dialog + + + + + 0 + 0 + 441 + 30 + + + + + 16777215 + 31 + + + + QWidget#widget +{ + background-color: rgb(245, 245, 245); +} +QLabel#label_icon +{ + image:url(:image/image_rsc/icon/admin.png); +} +QPushButton#pbtn_setting +{ + border-style: solid; + border-width: 0px; + border-radius: 0px; + background-color: rgba(223, 223, 223, 0); + image:url(:image/image_rsc/icon/setting.ico); +} +QPushButton#pbtn_minum +{ + border-style: solid; + border-width: 0px; + border-radius: 0px; + background-color: rgba(223, 223, 223, 0); + image:url(:image/image_rsc/icon/minum.ico); +} +QPushButton#pbtn_close +{ + border-style: solid; + border-width: 0px; + border-radius: 0px; + background-color: rgba(223, 223, 223, 0); + image:url(:image/image_rsc/icon/close.ico); +} +QPushButton::focus{outline: none;} +QPushButton#pbtn_setting::hover +{ + border-style: solid; + border-width: 0px; + border-radius: 0px; + background-color: rgba(223, 223, 223, 150); +} +QPushButton#pbtn_minum::hover +{ + border-style: solid; + border-width: 0px; + border-radius: 0px; + background-color: rgba(223, 223, 223, 150); +} +QPushButton#pbtn_close::hover +{ + border-style: solid; + border-width: 0px; + border-radius: 0px; + background-color: rgba(223, 223, 223, 150); +} + + + + + + + + 13 楷体 + 9 + 50 + false + false + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 112 + 10 + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + 40 + 40 + 321 + 191 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + account: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + host: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + port: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + LOG IN + + + true + + + + + + + EXIT + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + diff --git a/app/HGProductionTool/dialog_rootfuntion.cpp b/app/HGProductionTool/dialog_rootfuntion.cpp new file mode 100644 index 0000000..c01c7b2 --- /dev/null +++ b/app/HGProductionTool/dialog_rootfuntion.cpp @@ -0,0 +1,48 @@ +#include "dialog_rootfuntion.h" +#include "ui_dialog_rootfuntion.h" + +Dialog_rootFuntion::Dialog_rootFuntion(bool resetPassword, QWidget *parent) : + QDialog(parent), + m_resetPassword(resetPassword), + ui(new Ui::Dialog_rootFuntion) +{ + ui->setupUi(this); + + setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); + setWindowTitle(tr("Create account")); + + ui->lineEdit_password->setEchoMode(QLineEdit::EchoMode::Password); + + if (m_resetPassword) + { + setWindowTitle(tr("Reset password")); + ui->label_password->setText(tr("new password:")); + ui->label_account->setVisible(false); + ui->lineEdit_account->setVisible(false); + } +} + +Dialog_rootFuntion::~Dialog_rootFuntion() +{ + delete ui; +} + +QString Dialog_rootFuntion::getAccount() +{ + return ui->lineEdit_account->text(); +} + +QString Dialog_rootFuntion::getPassword() +{ + return ui->lineEdit_password->text(); +} + +void Dialog_rootFuntion::on_pbtn_ok_clicked() +{ + accept(); +} + +void Dialog_rootFuntion::on_pbtn_cancel_clicked() +{ + reject(); +} diff --git a/app/HGProductionTool/dialog_rootfuntion.h b/app/HGProductionTool/dialog_rootfuntion.h new file mode 100644 index 0000000..acb77d5 --- /dev/null +++ b/app/HGProductionTool/dialog_rootfuntion.h @@ -0,0 +1,32 @@ +#ifndef DIALOG_ROOTFUNTION_H +#define DIALOG_ROOTFUNTION_H + +#include + +namespace Ui { +class Dialog_rootFuntion; +} + +class Dialog_rootFuntion : public QDialog +{ + Q_OBJECT + +public: + explicit Dialog_rootFuntion(bool resetPassword, QWidget *parent = nullptr); + ~Dialog_rootFuntion(); + + QString getAccount(); + QString getPassword(); + +private slots: + void on_pbtn_ok_clicked(); + + void on_pbtn_cancel_clicked(); + +private: + Ui::Dialog_rootFuntion *ui; + + bool m_resetPassword; +}; + +#endif // DIALOG_ROOTFUNTION_H diff --git a/app/HGProductionTool/dialog_rootfuntion.ui b/app/HGProductionTool/dialog_rootfuntion.ui new file mode 100644 index 0000000..445a59f --- /dev/null +++ b/app/HGProductionTool/dialog_rootfuntion.ui @@ -0,0 +1,132 @@ + + + Dialog_rootFuntion + + + + 0 + 0 + 425 + 117 + + + + Dialog + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Account: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + password: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + diff --git a/app/HGProductionTool/form_maininterface.cpp b/app/HGProductionTool/form_maininterface.cpp new file mode 100644 index 0000000..0e74e9b --- /dev/null +++ b/app/HGProductionTool/form_maininterface.cpp @@ -0,0 +1,86 @@ +#include "form_maininterface.h" +#include "ui_form_maininterface.h" +#include +#include "imgfmt/HGImgFmt.h" +#include "HGUIGlobal.h" +#include "form_texttips.h" + +Form_mainInterface::Form_mainInterface(QWidget *parent) + : QWidget(parent) + , ui(new Ui::Form_mainInterface) +{ + ui->setupUi(this); + + QString path("../../doc/config.json"); + AnalysisJson analysisJson(path); + + std::vector list_jsonNode = analysisJson.GetNode(); + for(int i = 0; i < list_jsonNode.size(); ++i) + { + AnalysisJson::json_node node = list_jsonNode[i]; + ui->listWidget->addItem(node.title); + } + + this->setMinimumWidth(400); + ui->listWidget->setMinimumWidth(200); + ui->listWidget->setCurrentRow(0); + ui->pbtn_preStep->setEnabled(false); +} + +Form_mainInterface::~Form_mainInterface() +{ + delete ui; +} + +void Form_mainInterface::paintEvent(QPaintEvent *event) +{ + (void)event; + QPainter p(this); + p.setPen(QColor("gray")); + p.drawRect(0, 0, width() -1, height() -1); +} + +void Form_mainInterface::on_listWidget_currentRowChanged(int currentRow) +{ + ui->pbtn_preStep->setEnabled(ui->listWidget->currentRow() != 0); + ui->pbtn_nextStep->setEnabled(ui->listWidget->currentRow() != ui->listWidget->count() - 1); + + if (currentRow == 0) + { + Form_textTips *textTips = new Form_textTips(); + ui->stackedWidget->addWidget(textTips); + ui->stackedWidget->setCurrentWidget(textTips); + } + if (currentRow == 1) + { + HGImgView *m_view = new HGImgView(); + ui->stackedWidget->addWidget(m_view); + ui->stackedWidget->setCurrentWidget(m_view); + + HGImage img; + QString filename("C:\\Users\\yang'jia'xuan\\Pictures\\4.jpg"); + HGImgFmt_LoadImage(getStdFileName(filename).toStdString().c_str(), 0, 0, 0, 0, &img); + m_view->addImage(img); + } +} + +void Form_mainInterface::on_pbtn_preStep_clicked() +{ + ui->listWidget->setCurrentRow(ui->listWidget->currentRow() - 1); +} + +void Form_mainInterface::on_pbtn_nextStep_clicked() +{ + ui->listWidget->setCurrentRow(ui->listWidget->currentRow() + 1); +} + +void Form_mainInterface::on_pbtn_fail_clicked() +{ + ui->listWidget->item(ui->listWidget->currentRow())->setBackgroundColor("red"); +} + +void Form_mainInterface::on_pbtn_pass_clicked() +{ + ui->listWidget->item(ui->listWidget->currentRow())->setBackgroundColor("white"); +} + diff --git a/app/HGProductionTool/form_maininterface.h b/app/HGProductionTool/form_maininterface.h new file mode 100644 index 0000000..80a2acd --- /dev/null +++ b/app/HGProductionTool/form_maininterface.h @@ -0,0 +1,40 @@ +#ifndef FORM_MAININTERFACE_H +#define FORM_MAININTERFACE_H + +#include +#include "HGImgView.h" +#include "analysisjson.h" + +namespace Ui { +class Form_mainInterface; +} + +class Form_mainInterface : public QWidget +{ + Q_OBJECT + +public: + explicit Form_mainInterface(QWidget *parent = nullptr); + ~Form_mainInterface(); + +protected: + void paintEvent(QPaintEvent *event) override; + +private slots: + void on_listWidget_currentRowChanged(int currentRow); + + void on_pbtn_preStep_clicked(); + + void on_pbtn_nextStep_clicked(); + + void on_pbtn_fail_clicked(); + + void on_pbtn_pass_clicked(); + +private: + Ui::Form_mainInterface *ui; + + AnalysisJson *m_analysisJson; +}; + +#endif // FORM_MAININTERFACE_H diff --git a/app/HGProductionTool/form_maininterface.ui b/app/HGProductionTool/form_maininterface.ui new file mode 100644 index 0000000..50f7ffc --- /dev/null +++ b/app/HGProductionTool/form_maininterface.ui @@ -0,0 +1,124 @@ + + + Form_mainInterface + + + + 0 + 0 + 607 + 429 + + + + Form + + + + + + + + SN: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + -1 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Privious Step + + + + + + + PASS + + + + + + + FAIL + + + + + + + STOP + + + + + + + Next Step + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/app/HGProductionTool/form_texttips.cpp b/app/HGProductionTool/form_texttips.cpp new file mode 100644 index 0000000..83b1e7e --- /dev/null +++ b/app/HGProductionTool/form_texttips.cpp @@ -0,0 +1,45 @@ +#include "form_texttips.h" +#include "ui_form_texttips.h" + +Form_textTips::Form_textTips(QWidget *parent) + : QWidget(parent) + , ui(new Ui::Form_textTips) +{ + ui->setupUi(this); + QFont ft; + ft.setPointSize(35); + ui->textBrowser->setFont(ft); + ui->textBrowser->setText(tr("Please complete the calibration of ship type switch")); +} + +Form_textTips::~Form_textTips() +{ + delete ui; +} + +void Form_textTips::on_testItemChanged(int curRow) +{ + switch (curRow) + { + case 0: + ui->textBrowser->setText(tr("Please complete the calibration of ship type switch")); + break; + case 1: + ui->textBrowser->setText(tr("Please power on the device and observe the startup status")); + break; + case 2: + ui->textBrowser->setText(tr("Testing........")); + break; + default: + break; + } +} + + + + + + + + + diff --git a/app/HGProductionTool/form_texttips.h b/app/HGProductionTool/form_texttips.h new file mode 100644 index 0000000..1ab4985 --- /dev/null +++ b/app/HGProductionTool/form_texttips.h @@ -0,0 +1,26 @@ +#ifndef FORM_TEXTTIPS_H +#define FORM_TEXTTIPS_H + +#include + +namespace Ui { +class Form_textTips; +} + +class Form_textTips : public QWidget +{ + Q_OBJECT + +public: + explicit Form_textTips(QWidget *parent = nullptr); + ~Form_textTips(); + +public slots: + void on_testItemChanged(int curRow); + + +private: + Ui::Form_textTips *ui; +}; + +#endif // FORM_TEXTTIPS_H diff --git a/app/HGProductionTool/form_texttips.ui b/app/HGProductionTool/form_texttips.ui new file mode 100644 index 0000000..da1ae54 --- /dev/null +++ b/app/HGProductionTool/form_texttips.ui @@ -0,0 +1,24 @@ + + + Form_textTips + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + + + diff --git a/app/HGProductionTool/image_rsc/icon/close.ico b/app/HGProductionTool/image_rsc/icon/close.ico new file mode 100644 index 0000000..e275b3d Binary files /dev/null and b/app/HGProductionTool/image_rsc/icon/close.ico differ diff --git a/app/HGProductionTool/image_rsc/icon/minum.ico b/app/HGProductionTool/image_rsc/icon/minum.ico new file mode 100644 index 0000000..9dfe231 Binary files /dev/null and b/app/HGProductionTool/image_rsc/icon/minum.ico differ diff --git a/app/HGProductionTool/image_rsc/icon/setting.ico b/app/HGProductionTool/image_rsc/icon/setting.ico new file mode 100644 index 0000000..96581ec Binary files /dev/null and b/app/HGProductionTool/image_rsc/icon/setting.ico differ diff --git a/app/HGProductionTool/image_rsc/logo/logo.ico b/app/HGProductionTool/image_rsc/logo/logo.ico new file mode 100644 index 0000000..bb06227 Binary files /dev/null and b/app/HGProductionTool/image_rsc/logo/logo.ico differ diff --git a/app/HGProductionTool/main.cpp b/app/HGProductionTool/main.cpp new file mode 100644 index 0000000..b0a200e --- /dev/null +++ b/app/HGProductionTool/main.cpp @@ -0,0 +1,40 @@ +#include "mainwindow.h" + +#include +#include +#include "base/HGBase.h" +#include "dialog_login.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + QTranslator translator_qt; + if (translator_qt.load(":translation/ProductionTool_zh_CN.qm")) + a.installTranslator(&translator_qt); + + while (1) + { + Dialog_logIn login; + if (login.exec()) + { + HGPdtToolDbUserMgr userMgr = login.GetUserMgr(); + assert(nullptr != userMgr); + + MainWindow w(userMgr); + w.showMaximized(); + a.exec(); + + if (w.isExitApp()) + { + break; + } + } + else + { + break; + } + } + + return 0; +} diff --git a/app/HGProductionTool/mainwindow.cpp b/app/HGProductionTool/mainwindow.cpp new file mode 100644 index 0000000..e1512e2 --- /dev/null +++ b/app/HGProductionTool/mainwindow.cpp @@ -0,0 +1,154 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include "base/HGBase.h" +#include "HGUIGlobal.h" +#include "dialog_login.h" +#include "dialog_changepwd.h" +#include "dialog_accountmanage.h" + +MainWindow::MainWindow(HGPdtToolDbUserMgr userMgr, QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) + , m_pdtToolDbuserMgr(userMgr) + , m_form_mainInterface(nullptr) + , m_top_splitter(nullptr) + , m_bot_splitter(nullptr) + , m_splitterCount(1) + , m_isLogOut(false) +{ + ui->setupUi(this); + setWindowIcon(QIcon(":image/image_rsc/logo/logo.ico")); + + HGUInt userType = 0; + HGPdtToolDb_GetUserType(m_pdtToolDbuserMgr, &userType); + if (userType == HGPDTTOOLDB_USERTYPE_NORMAL) + ui->act_manage->setVisible(false); + + HGChar userName[128]; + HGPdtToolDb_GetUserName(m_pdtToolDbuserMgr, userName, 128); + setWindowTitle(userName); + + m_top_splitter = new QSplitter(Qt::Horizontal); + m_bot_splitter = new QSplitter(Qt::Horizontal); + m_form_mainInterface = new Form_mainInterface(); + m_top_splitter->addWidget(m_form_mainInterface); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addWidget(m_top_splitter); + vLayout->addWidget(m_bot_splitter); + vLayout->setStretch(0, 1); + vLayout->setStretch(1, 0); + this->centralWidget()->setLayout(vLayout); +} + +MainWindow::~MainWindow() +{ + HGPdtToolDb_DestroyUserMgr(m_pdtToolDbuserMgr); + m_pdtToolDbuserMgr = NULL; + + delete ui; +} + +bool MainWindow::isExitApp() +{ + return !m_isLogOut; +} + +void MainWindow::on_act_newDevice_triggered() +{ + m_splitterCount++; + switch (m_splitterCount) + { + case 2: + { + Form_mainInterface *form_mainInterface = new Form_mainInterface(); + m_top_splitter->addWidget(form_mainInterface); + + break; + } + + case 3: + { + Form_mainInterface *form_mainInterface = new Form_mainInterface(); + m_bot_splitter->addWidget(form_mainInterface); + reinterpret_cast(this->centralWidget()->layout())->setStretch(1, 1); + break; + } + + case 4: + { + Form_mainInterface *form_mainInterface = new Form_mainInterface(); + m_bot_splitter->addWidget(form_mainInterface); + break; + } + + case 5: + QMessageBox::information(this, tr("tips"), tr("cannot create more table")); + return; + break; + + default: + break; + } +} + +void MainWindow::on_act_manage_triggered() +{ + Dialog_accountManage dlg(m_pdtToolDbuserMgr, this); + dlg.exec(); +} + +void MainWindow::on_act_changePwd_triggered() +{ + Dialog_changePwd dlg(m_pdtToolDbuserMgr, this); + dlg.exec(); +} + +void MainWindow::on_act_export_triggered() +{ + HGChar cfgPath[256]= {0}; + HGBase_GetConfigPath(cfgPath, 256); + strcat(cfgPath, "1.xls"); + HGPdtToolDb_Export(m_pdtToolDbuserMgr, getStdString(cfgPath).c_str()); +} + +void MainWindow::on_act_logOut_triggered() +{ + HGPdtToolDb_DestroyUserMgr(m_pdtToolDbuserMgr); + m_isLogOut = true; + close(); +} + + +void MainWindow::on_act_close_triggered() +{ + close(); +} + +QString MainWindow::getLogInfo(HGResult ret) +{ + QString str; + if (HGPDTTOOLDB_ERR_INVALID_USER == ret) + { + str = tr("Illegal user"); + } + else if (HGPDTTOOLDB_ERR_WRONG_PASSWORD == ret) + { + str = tr("Wrong password"); + } + else if (HGPDTTOOLDB_ERR_DATABASE == ret) + { + str = tr("Database error"); + } + else if (HGPDTTOOLDB_ERR_CONNECT == ret) + { + str = tr("connect error"); + } + else + { + str = tr("Failed"); + } + + return str; +} diff --git a/app/HGProductionTool/mainwindow.h b/app/HGProductionTool/mainwindow.h new file mode 100644 index 0000000..59ed8f5 --- /dev/null +++ b/app/HGProductionTool/mainwindow.h @@ -0,0 +1,53 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H +#include +#include "form_maininterface.h" +#include "form_texttips.h" +#include +#include +#include "HGPdtToolDb.h" + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(HGPdtToolDbUserMgr userMgr, QWidget *parent = nullptr); + ~MainWindow(); + + static QString getLogInfo(HGResult ret); + + bool isExitApp(); + +private slots: + void on_act_newDevice_triggered(); + + void on_act_manage_triggered(); + + void on_act_changePwd_triggered(); + + void on_act_export_triggered(); + + void on_act_logOut_triggered(); + + void on_act_close_triggered(); + +private: + QSplitter *m_top_splitter; + QSplitter *m_bot_splitter; + + int m_splitterCount; + bool m_isLogOut; + +private: + Ui::MainWindow *ui; + HGPdtToolDbUserMgr m_pdtToolDbuserMgr; + + Form_mainInterface *m_form_mainInterface; + +}; +#endif // MAINWINDOW_H diff --git a/app/HGProductionTool/mainwindow.ui b/app/HGProductionTool/mainwindow.ui new file mode 100644 index 0000000..5639c15 --- /dev/null +++ b/app/HGProductionTool/mainwindow.ui @@ -0,0 +1,81 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + 0 + 0 + 800 + 22 + + + + + menu_device + + + + + + + menu_user + + + + + + + + + + + + + + + act_newDevice + + + + + act_manage + + + + + act_changePwd + + + + + act_export + + + + + act_logOut + + + + + act_close + + + + + + diff --git a/app/modules/base/HGBase.h b/app/modules/base/HGBase.h new file mode 100644 index 0000000..afcd65f --- /dev/null +++ b/app/modules/base/HGBase.h @@ -0,0 +1,24 @@ +#ifndef __HGBASE_H__ +#define __HGBASE_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" +#include "HGBase64.h" +#include "HGDes.h" +#include "HGMd5.h" +#include "HGLock.h" +#include "HGEvent.h" +#include "HGDll.h" +#include "HGLog.h" +#include "HGConsole.h" +#include "HGBuffer.h" +#include "HGImage.h" +#include "HGThread.h" +#include "HGUtility.h" +#include "HGInfo.h" +#include "HGIni.h" +#include "HGMsgPump.h" +#include "HGTime.h" +#include "HGNamedPipe.h" + +#endif /* __HGBASE_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGBase64.cpp b/app/modules/base/HGBase64.cpp new file mode 100644 index 0000000..fb188a0 --- /dev/null +++ b/app/modules/base/HGBase64.cpp @@ -0,0 +1,255 @@ +#include "HGBase64.h" +#include "HGInc.h" + +HGResult HGAPI HGBase_Base64Encode(const HGByte* originalData, HGSize originalSize, + HGByte* base64Data, HGSize* base64Size) +{ + if (NULL == originalData || 0 == originalSize) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL != base64Data) + { + static const HGByte base64Table[] = + { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' + }; + + HGSize numberOfCycles = originalSize / 3; + + //#pragma omp parallel for + for (HGSize i = 0; i < numberOfCycles; ++i) + { + const HGByte* originalDataEx = originalData + i * 3; + HGByte* base64DataEx = base64Data + i * 4; + + HGUInt temp = (((HGUInt)originalDataEx[0] << 16) | ((HGUInt)originalDataEx[1] << 8) + | ((HGUInt)originalDataEx[2])) & 0x00FFFFFF; + base64DataEx[0] = base64Table[(temp >> 18) & 0x3F]; + base64DataEx[1] = base64Table[(temp >> 12) & 0x3F]; + base64DataEx[2] = base64Table[(temp >> 6) & 0x3F]; + base64DataEx[3] = base64Table[temp & 0x3F]; + } + + const HGByte* originalDataEx = originalData + numberOfCycles * 3; + HGByte* base64DataEx = base64Data + numberOfCycles * 4; + + HGSize sizeOfRemaining = originalSize - numberOfCycles * 3; + if (1 == sizeOfRemaining) + { + HGUInt temp = ((HGUInt)originalDataEx[0] << 16) & 0x00FF0000; + base64DataEx[0] = base64Table[(temp >> 18) & 0x3F]; + base64DataEx[1] = base64Table[(temp >> 12) & 0x3F]; + base64DataEx[2] = '='; + base64DataEx[3] = '='; + } + else if (2 == sizeOfRemaining) + { + HGUInt temp = (((HGUInt)originalDataEx[0] << 16) | ((HGUInt)originalDataEx[1] << 8)) & 0x00FFFF00; + base64DataEx[0] = base64Table[(temp >> 18) & 0x3F]; + base64DataEx[1] = base64Table[(temp >> 12) & 0x3F]; + base64DataEx[2] = base64Table[(temp >> 6) & 0x3F]; + base64DataEx[3] = '='; + } + } + + if (NULL != base64Size) + { + HGSize newSize = (originalSize / 3) * 4; + if (0 != originalSize % 3) + { + newSize += 4; + } + + *base64Size = newSize; + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_Base64Decode(const HGByte* base64Data, HGSize base64Size, + HGByte* originalData, HGSize* originalSize) +{ + if (NULL == base64Data || 0 == base64Size) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL != originalData) + { + static const HGByte base64Table_1[] = + { + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 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, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64 + }; + + HGSize numberOfCycles = (base64Size - 1) / 4; + + //#pragma omp parallel for + for (HGSize i = 0; i < numberOfCycles; ++i) + { + const HGByte* base64DataEx = base64Data + i * 4; + HGByte* originalDataEx = originalData + i * 3; + + HGUInt t0 = base64Table_1[base64DataEx[0]]; + HGUInt t1 = base64Table_1[base64DataEx[1]]; + HGUInt t2 = base64Table_1[base64DataEx[2]]; + HGUInt t3 = base64Table_1[base64DataEx[3]]; + + originalDataEx[0] = ((t0 << 2) | (t1 >> 4)) & 0xFF; + originalDataEx[1] = ((t1 << 4) | (t2 >> 2)) & 0xFF; + originalDataEx[2] = ((t2 << 6) | t3) & 0xFF; + } + + const HGByte* base64DataEx = base64Data + numberOfCycles * 4; + HGByte* originalDataEx = originalData + numberOfCycles * 3; + + HGSize sizeOfRemaining = base64Size - numberOfCycles * 4; + if (2 == sizeOfRemaining) + { + if ('=' != base64DataEx[0] && '=' != base64DataEx[1]) + { + HGUInt t0 = base64Table_1[base64DataEx[0]]; + HGUInt t1 = base64Table_1[base64DataEx[1]]; + + originalDataEx[0] = ((t0 << 2) | (t1 >> 4)) & 0xFF; + } + } + else if (3 == sizeOfRemaining) + { + if ('=' != base64DataEx[0] && '=' != base64DataEx[1]) + { + HGUInt t0 = base64Table_1[base64DataEx[0]]; + HGUInt t1 = base64Table_1[base64DataEx[1]]; + HGUInt t2 = base64Table_1[base64DataEx[2]]; + + if ('=' == base64DataEx[2]) + { + originalDataEx[0] = ((t0 << 2) | (t1 >> 4)) & 0xFF; + } + else + { + originalDataEx[0] = ((t0 << 2) | (t1 >> 4)) & 0xFF; + originalDataEx[1] = ((t1 << 4) | (t2 >> 2)) & 0xFF; + } + } + } + else if (4 == sizeOfRemaining) + { + if ('=' != base64DataEx[0] && '=' != base64DataEx[1]) + { + HGUInt t0 = base64Table_1[base64DataEx[0]]; + HGUInt t1 = base64Table_1[base64DataEx[1]]; + HGUInt t2 = base64Table_1[base64DataEx[2]]; + HGUInt t3 = base64Table_1[base64DataEx[3]]; + + if ('=' == base64DataEx[2] && '=' == base64DataEx[3]) + { + originalDataEx[0] = ((t0 << 2) | (t1 >> 4)) & 0xFF; + } + else if ('=' != base64DataEx[2] && '=' == base64DataEx[3]) + { + originalDataEx[0] = ((t0 << 2) | (t1 >> 4)) & 0xFF; + originalDataEx[1] = ((t1 << 4) | (t2 >> 2)) & 0xFF; + } + else if ('=' != base64DataEx[2] && '=' != base64DataEx[3]) + { + originalDataEx[0] = ((t0 << 2) | (t1 >> 4)) & 0xFF; + originalDataEx[1] = ((t1 << 4) | (t2 >> 2)) & 0xFF; + originalDataEx[2] = ((t2 << 6) | t3) & 0xFF; + } + } + } + } + + if (NULL != originalSize) + { + HGSize numberOfCycles = (base64Size - 1) / 4; + const HGByte* base64DataEx = base64Data + numberOfCycles * 4; + + HGSize newSize = numberOfCycles * 3; + + HGSize sizeOfRemaining = base64Size - numberOfCycles * 4; + if (2 == sizeOfRemaining) + { + if ('=' != base64DataEx[0] && '=' != base64DataEx[1]) + { + newSize += 1; + } + } + else if (3 == sizeOfRemaining) + { + if ('=' != base64DataEx[0] && '=' != base64DataEx[1]) + { + if ('=' == base64DataEx[2]) + { + newSize += 1; + } + else + { + newSize += 2; + } + } + } + else if (4 == sizeOfRemaining) + { + if ('=' != base64DataEx[0] && '=' != base64DataEx[1]) + { + if ('=' == base64DataEx[2] && '=' == base64DataEx[3]) + { + newSize += 1; + } + else if ('=' != base64DataEx[2] && '=' == base64DataEx[3]) + { + newSize += 2; + } + else if ('=' != base64DataEx[2] && '=' != base64DataEx[3]) + { + newSize += 3; + } + } + } + + *originalSize = newSize; + } + + return HGBASE_ERR_OK; +} \ No newline at end of file diff --git a/app/modules/base/HGBase64.h b/app/modules/base/HGBase64.h new file mode 100644 index 0000000..2b8c120 --- /dev/null +++ b/app/modules/base/HGBase64.h @@ -0,0 +1,34 @@ +#ifndef __HGBASE64_H__ +#define __HGBASE64_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* Base64编码 +* 参数: +* 1) originalData: in, 原始数据地址 +* 2) originalSize: in, 原始数据长度 +* 3) base64Data: out, base64地址 +* 4) base64Size: out, 编码后base64长度 +* 说明: +* 1) 该函数的调用需要分两次,第一次base64Data为NULL,base64Size不为NULL, 获取编码后base64长度 +* 2) 分配足够的内存后,然后调用第二次,此时base64Data为分配的地址 +*/ +HGEXPORT HGResult HGAPI HGBase_Base64Encode(const HGByte* originalData, HGSize originalSize, + HGByte* base64Data, HGSize* base64Size); + +/* Base64解码 +* 参数: +* 1) base64Data: in, base64地址 +* 2) base64Size: in, base64长度 +* 3) originalData: out, 原始数据地址 +* 4) originalSize: out, 解码后原始数据长度 +* 说明: +* 1) 该函数的调用需要分两次,第一次originalData为NULL,originalSize不为NULL, 获取解码后原始数据长度 +* 2) 分配足够的内存后,然后调用第二次,此时originalData为分配的地址 +* 3) base64Data中的数据必须是标准Base64字符, 不能有其他字符,比如\r或\n等 +*/ +HGEXPORT HGResult HGAPI HGBase_Base64Decode(const HGByte* base64Data, HGSize base64Size, + HGByte* originalData, HGSize* originalSize); + +#endif /* __HGBASE64_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGBaseErr.h b/app/modules/base/HGBaseErr.h new file mode 100644 index 0000000..b06338e --- /dev/null +++ b/app/modules/base/HGBaseErr.h @@ -0,0 +1,40 @@ +#ifndef __HGBASEERR_H__ +#define __HGBASEERR_H__ + +/* 无错误 */ +#define HGBASE_ERR_OK 0x00000000L + +/* 一般错误 */ +#define HGBASE_ERR_FAIL 0x00000001L + +/* 内存不足 */ +#define HGBASE_ERR_OUTOFMEMORY 0x00000002L + +/* 参数非法 */ +#define HGBASE_ERR_INVALIDARG 0x00000003L + +/* 无访问权限 */ +#define HGBASE_ERR_ACCESSDENIED 0x00000004L + +/* 数据非法 */ +#define HGBASE_ERR_INVALIDDATA 0x00000005L + +/* 未实现 */ +#define HGBASE_ERR_NOTIMPL 0x00000006L + +/* 不支持该功能 */ +#define HGBASE_ERR_NOTSUPPORT 0x00000007L + +/* 超时 */ +#define HGBASE_ERR_TIMEOUT 0x00000008L + +/* 文件不存在 */ +#define HGBASE_ERR_FILENOTEXIST 0x00000009L + +/* 加载动态库失败 */ +#define HGBASE_ERR_LOADLIBRARY 0x0000000AL + +/* 文件错误 */ +#define HGBASE_ERR_FILEERROR 0x0000000BL + +#endif /* __HGBASEERR_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGBuffer.cpp b/app/modules/base/HGBuffer.cpp new file mode 100644 index 0000000..4b49b04 --- /dev/null +++ b/app/modules/base/HGBuffer.cpp @@ -0,0 +1,149 @@ +#include "HGBuffer.h" +#include "HGInc.h" + +struct HGBufferImpl +{ + HGBufferImpl() + { + m_data = NULL; + m_size = 0; + m_alloc = HGFALSE; + } + + ~HGBufferImpl() + { + if (m_alloc) + { + free(m_data); + m_data = NULL; + } + } + + HGByte* m_data; + HGUSize m_size; + HGBool m_alloc; +}; + +HGResult HGAPI HGBase_CreateBuffer(HGUSize size, HGBuffer* buffer) +{ + if (0 == size || NULL == buffer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGByte* data = (HGByte*)malloc(size); + if (NULL == data) + { + return HGBASE_ERR_OUTOFMEMORY; + } + + HGBufferImpl* bufferImpl = new HGBufferImpl; + bufferImpl->m_data = data; + bufferImpl->m_size = size; + bufferImpl->m_alloc = HGTRUE; + + *buffer = (HGBuffer)bufferImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CreateBufferFromData(const HGByte* data, HGUSize size, HGBuffer* buffer) +{ + if (NULL == data || 0 == size || NULL == buffer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGByte* data2 = (HGByte*)malloc(size); + if (NULL == data2) + { + return HGBASE_ERR_OUTOFMEMORY; + } + + memcpy(data2, data, size); + + HGBufferImpl* bufferImpl = new HGBufferImpl; + bufferImpl->m_data = data2; + bufferImpl->m_size = size; + bufferImpl->m_alloc = HGTRUE; + + *buffer = (HGBuffer)bufferImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CreateBufferWithData(HGByte* data, HGUSize size, HGBuffer* buffer) +{ + if (NULL == data || 0 == size || NULL == buffer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGBufferImpl* bufferImpl = new HGBufferImpl; + bufferImpl->m_data = data; + bufferImpl->m_size = size; + bufferImpl->m_alloc = HGFALSE; + + *buffer = (HGBuffer)bufferImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CloneBuffer(HGBuffer srcBuffer, HGBuffer* buffer) +{ + if (NULL == srcBuffer || NULL == buffer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGBufferImpl* srcBufferImpl = (HGBufferImpl*)srcBuffer; + + HGByte* data = (HGByte*)malloc(srcBufferImpl->m_size); + if (NULL == data) + { + return HGBASE_ERR_OUTOFMEMORY; + } + + memcpy(data, srcBufferImpl->m_data, srcBufferImpl->m_size); + + HGBufferImpl* bufferImpl = new HGBufferImpl; + bufferImpl->m_data = data; + bufferImpl->m_size = srcBufferImpl->m_size; + bufferImpl->m_alloc = HGTRUE; + + *buffer = (HGBuffer)bufferImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_DestroyBuffer(HGBuffer buffer) +{ + if (NULL == buffer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGBufferImpl* bufferImpl = (HGBufferImpl*)buffer; + delete bufferImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetBufferData(HGBuffer buffer, HGByte** data) +{ + if (NULL == buffer || NULL == data) + { + return HGBASE_ERR_INVALIDARG; + } + + HGBufferImpl* bufferImpl = (HGBufferImpl*)buffer; + *data = bufferImpl->m_data; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetBufferSize(HGBuffer buffer, HGUSize* size) +{ + if (NULL == buffer || NULL == size) + { + return HGBASE_ERR_INVALIDARG; + } + + HGBufferImpl* bufferImpl = (HGBufferImpl*)buffer; + *size = bufferImpl->m_size; + return HGBASE_ERR_OK; +} \ No newline at end of file diff --git a/app/modules/base/HGBuffer.h b/app/modules/base/HGBuffer.h new file mode 100644 index 0000000..0856aa2 --- /dev/null +++ b/app/modules/base/HGBuffer.h @@ -0,0 +1,76 @@ +#ifndef __HGBUFFER_H__ +#define __HGBUFFER_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGBuffer); + +/* 创建新的缓冲区 +* 参数: +* 1) size: in, 缓冲区大小, 单位字节 +* 2) buffer: out, 新缓冲区句柄 +* 说明: +* 1) 内部会分配size字节大小的内存 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateBuffer(HGUSize size, HGBuffer* buffer); + +/* 通过已有数据创建新的缓冲区 +* 参数: +* 1) data: in, 已有的数据地址 +* 2) size: in, 已有的数据大小, 单位字节 +* 3) buffer: out, 新缓冲区句柄 +* 说明: +* 1) 内部会分配size字节大小的内存, 新的缓冲区创建完成时, 会将data中的数据拷贝过去 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateBufferFromData(const HGByte* data, HGUSize size, HGBuffer* buffer); + +/* 通过已有数据创建新的缓冲区(不分配内存, 不拷贝数据) +* 参数: +* 1) data: in, 已有的数据地址 +* 2) size: in, 已有的数据大小, 单位字节 +* 3) buffer: out, 新缓冲区句柄 +* 说明: +* 1) 内部不会分配内存, 将直接使用原始数据 +* 2) 需保证缓冲区销毁前原始数据一直有效 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateBufferWithData(HGByte* data, HGUSize size, HGBuffer* buffer); + +/* 通过现有缓冲区创建新的缓冲区 +* 参数: +* 1) srcBuffer: in, 已有缓冲区 +* 2) buffer: out, 新缓冲区句柄 +* 说明: +* 1) 内部会分配现有缓冲区的size字节大小的内存, 新缓冲区创建完成时, 会将现有缓冲区中的数据拷贝过去 +*/ +HGEXPORT HGResult HGAPI HGBase_CloneBuffer(HGBuffer srcBuffer, HGBuffer* buffer); + +/* 销毁缓冲区 +* 参数: +* 1) buffer: in, 缓冲区句柄 +* 说明: +* 1) 如果内部分配了内存, 销毁的时候会自动释放该内存 +*/ +HGEXPORT HGResult HGAPI HGBase_DestroyBuffer(HGBuffer buffer); + +/* 获取缓冲区数据地址 +* 参数: +* 1) buffer: in, 缓冲区句柄 +* 2) data: out, 数据地址 +* 说明: +* 1) 如果内部分配了内存, 返回的是分配的内存地址 +* 2) 如果内部没有分配内存, 返回的则是原始数据的地址 +*/ +HGEXPORT HGResult HGAPI HGBase_GetBufferData(HGBuffer buffer, HGByte** data); + +/* 获取缓冲区数据大小 +* 参数: +* 1) buffer: in, 缓冲区句柄 +* 2) size: out, 数据长度 +* 说明: +* 1) 如果内部分配了内存, 返回的是分配的内存大小 +* 2) 如果内部没有分配内存, 返回的则是原始数据的大小 +*/ +HGEXPORT HGResult HGAPI HGBase_GetBufferSize(HGBuffer buffer, HGUSize* size); + +#endif /* __HGBUFFER_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGConsole.cpp b/app/modules/base/HGConsole.cpp new file mode 100644 index 0000000..48e5ead --- /dev/null +++ b/app/modules/base/HGConsole.cpp @@ -0,0 +1,78 @@ +#include "HGConsole.h" +#include "HGInc.h" + +struct HGConsoleImpl +{ + HGConsoleImpl() + { +#if defined(HG_CMP_MSC) + m_bAllocConsole = FALSE; + m_hConsole = INVALID_HANDLE_VALUE; +#endif + } + + ~HGConsoleImpl() + { +#if defined(HG_CMP_MSC) + if (INVALID_HANDLE_VALUE != m_hConsole) + m_hConsole = INVALID_HANDLE_VALUE; + if (m_bAllocConsole) + { + FreeConsole(); + m_bAllocConsole = FALSE; + } +#endif + } + +#if defined(HG_CMP_MSC) + BOOL m_bAllocConsole; + HANDLE m_hConsole; +#endif +}; + +HGResult HGAPI HGBase_OpenConsole(HGConsole* console) +{ + if (NULL == console) + { + return HGBASE_ERR_INVALIDARG; + } + + HGConsoleImpl* consoleImpl = new HGConsoleImpl; +#if defined(HG_CMP_MSC) + consoleImpl->m_bAllocConsole = AllocConsole(); + consoleImpl->m_hConsole = GetStdHandle(STD_OUTPUT_HANDLE); +#endif + *console = (HGConsole)consoleImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CloseConsole(HGConsole console) +{ + if (NULL == console) + { + return HGBASE_ERR_INVALIDARG; + } + + HGConsoleImpl* consoleImpl = (HGConsoleImpl*)console; + delete consoleImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_WriteConsole(HGConsole console, const HGChar* info) +{ + if (NULL == console || NULL == info || '\0' == *info) + { + return HGBASE_ERR_INVALIDARG; + } + + HGConsoleImpl* consoleImpl = (HGConsoleImpl*)console; +#if defined(HG_CMP_MSC) + DWORD dwNumberOfCharsWritten; + WriteConsoleA(consoleImpl->m_hConsole, info, (DWORD)strlen(info), &dwNumberOfCharsWritten, NULL); + WriteConsoleA(consoleImpl->m_hConsole, "\r\n", (DWORD)strlen("\r\n"), &dwNumberOfCharsWritten, NULL); +#else + printf(info); + printf("\n"); +#endif + return HGBASE_ERR_OK; +} \ No newline at end of file diff --git a/app/modules/base/HGConsole.h b/app/modules/base/HGConsole.h new file mode 100644 index 0000000..566f4ae --- /dev/null +++ b/app/modules/base/HGConsole.h @@ -0,0 +1,32 @@ +#ifndef __HGCONSOLE_H__ +#define __HGCONSOLE_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGConsole); + +/* 开启控制台 +* 参数: +* 1) log: out, 控制台句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_OpenConsole(HGConsole *console); + +/* 关闭控制台 +* 参数: +* 1) log: in, 控制台句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_CloseConsole(HGConsole console); + +/* 写控制台信息 +* 参数: +* 1) log: in, 控制台句柄 +* 2) info: in, 信息, 一次一行, info无需加换行符 +* 说明: +* 1) 该函数不是线程安全的, 在不同线程调用的时候, 需要加锁 +*/ +HGEXPORT HGResult HGAPI HGBase_WriteConsole(HGConsole console, const HGChar* info); + +#endif /* __HGCONSOLE_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGCrash.cpp b/app/modules/base/HGCrash.cpp new file mode 100644 index 0000000..ac36764 --- /dev/null +++ b/app/modules/base/HGCrash.cpp @@ -0,0 +1,66 @@ +#include "HGCrash.h" +#include "HGInc.h" +#if defined(HG_CMP_MSC) +#include +#endif + +static HGCrashFunc g_crashFunc = NULL; +static HGPointer g_crashParam = NULL; +#if defined(HG_CMP_MSC) +static _EXCEPTION_POINTERS* g_exceptionInfo = NULL; +#endif + +#if defined(HG_CMP_MSC) +static LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS* exceptionInfo) +{ + g_exceptionInfo = exceptionInfo; + if (NULL != g_crashFunc) + g_crashFunc(exceptionInfo->ExceptionRecord->ExceptionAddress, g_crashParam); + g_exceptionInfo = NULL; + + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + +HGResult HGAPI HGBase_RegisterCrashFunc(HGCrashFunc func, HGPointer param) +{ + if (NULL == func) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + g_crashFunc = func; + g_crashParam = param; + SetUnhandledExceptionFilter(UnhandledExceptionFilterEx); + return HGBASE_ERR_OK; +#else + return HGBASE_ERR_NOTIMPL; +#endif +} + +HGResult HGAPI HGBase_MakeCrashFile(const HGChar* filePath) +{ +#if defined(HG_CMP_MSC) + if (NULL == g_exceptionInfo) + { + return HGBASE_ERR_FAIL; + } + + HANDLE hFile = CreateFileA(filePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile) + { + return HGBASE_ERR_ACCESSDENIED; + } + + MINIDUMP_EXCEPTION_INFORMATION mdei; + mdei.ThreadId = GetCurrentThreadId(); + mdei.ExceptionPointers = g_exceptionInfo; + mdei.ClientPointers = TRUE; + MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, NULL); + CloseHandle(hFile); + return HGBASE_ERR_OK; +#else + return HGBASE_ERR_NOTIMPL; +#endif +} \ No newline at end of file diff --git a/app/modules/base/HGCrash.h b/app/modules/base/HGCrash.h new file mode 100644 index 0000000..69045d6 --- /dev/null +++ b/app/modules/base/HGCrash.h @@ -0,0 +1,13 @@ +#ifndef __HGCRASH_H__ +#define __HGCRASH_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +typedef void (HGAPI *HGCrashFunc)(HGPointer crashAddr, HGPointer param); + +HGEXPORT HGResult HGAPI HGBase_RegisterCrashFunc(HGCrashFunc func, HGPointer param); + +HGEXPORT HGResult HGAPI HGBase_MakeCrashFile(const HGChar *filePath); + +#endif /* __HGCRASH_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGDef.h b/app/modules/base/HGDef.h new file mode 100644 index 0000000..76d6036 --- /dev/null +++ b/app/modules/base/HGDef.h @@ -0,0 +1,146 @@ +#ifndef __HGDEF_H__ +#define __HGDEF_H__ + +/**************************************************************************** + * Platform Dependent Definitions and Typedefs * + ****************************************************************************/ + + /* Microsoft C/C++ Compiler */ +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) || defined (_WINDOWS) + + #define HG_CMP_MSC + #if defined(_WIN64) || defined(WIN64) + #define HG_64BIT + #elif defined(_WIN32) || defined(WIN32) + #define HG_32BIT + #endif + +/* Apple Compiler (which is GNU now) */ +#elif defined(__APPLE__) + + #define HG_CMP_XCODE + #define HG_64BIT + +/* GNU C/C++ Compiler */ +#elif defined(__GNUC__) + + #define HG_CMP_GNU + #if defined(__alpha__) || defined(__ia64__) || defined(__ppc64__) || defined(__s390x__) || defined(__x86_64__) + #define HG_64BIT + #else + #define HG_32BIT + #endif + +/* Unrecognized */ +#else + + #error Unrecognized compiler + +#endif + +#if defined(HG_CMP_MSC) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif +#endif + +/* type defines */ +typedef void HGVoid; +typedef char HGChar; +typedef unsigned char HGByte; +typedef short HGShort; +typedef unsigned short HGUShort; +typedef int HGInt; +typedef unsigned int HGUInt; +typedef long long HGLonglong; +typedef unsigned long long HGULonglong; +typedef void* HGPointer; +typedef HGInt HGBool; +typedef float HGFloat; +typedef double HGDouble; +#ifdef HG_64BIT + typedef HGLonglong HGSize; + typedef HGULonglong HGUSize; +#else + typedef HGInt HGSize; + typedef HGUInt HGUSize; +#endif + +typedef HGUInt HGColor; + +#define HG_MAKECOLOR(r, g, b, a) (HGColor)(((HGUInt)a << 24) | ((HGUInt)b << 16) | ((HGUInt)g << 8) | (HGUInt)r) +#define HG_GETCOLOR_R(color) (HGUInt)((HGColor)color & 0xFF) +#define HG_GETCOLOR_G(color) (HGUInt)(((HGColor)color >> 8) & 0xFF) +#define HG_GETCOLOR_B(color) (HGUInt)(((HGColor)color >> 16) & 0xFF) +#define HG_GETCOLOR_A(color) (HGUInt)(((HGColor)color >> 24) & 0xFF) + +/* error code */ +typedef HGUInt HGResult; + +#define HGTRUE 1 +#define HGFALSE 0 + +#ifndef HGMAX + #define HGMAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef HGMIN + #define HGMIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#if defined(HG_CMP_MSC) + #ifdef __cplusplus + #define HGEXPORT extern "C" + #else + #define HGEXPORT + #endif /* __cplusplus */ + #define HGAPI __stdcall + #define HGAPIV __cdecl +#else + #ifdef __cplusplus + #define HGEXPORT extern "C" __attribute ((visibility("default"))) + #else + #define HGEXPORT __attribute ((visibility("default"))) + #endif /* __cplusplus */ + #define HGAPI + #define HGAPIV +#endif + +#define HG_DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGInt left; + HGInt top; + HGInt right; + HGInt bottom; +}HGRect; + +typedef struct +{ + HGFloat left; + HGFloat top; + HGFloat right; + HGFloat bottom; +}HGRectF; + +typedef struct +{ + HGInt x; + HGInt y; +}HGPoint; + +typedef struct +{ + HGFloat x; + HGFloat y; +}HGPointF; + +#pragma pack(pop) + +#endif /* __HGDEF_H__ */ diff --git a/app/modules/base/HGDes.cpp b/app/modules/base/HGDes.cpp new file mode 100644 index 0000000..16f1f31 --- /dev/null +++ b/app/modules/base/HGDes.cpp @@ -0,0 +1,472 @@ +#include "HGDes.h" +#include "HGInc.h" + +/* 初始置换表IP */ +static HGByte IP_Table[64] = +{ + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + 56, 48, 40, 32, 24, 16, 8, 0, + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6 +}; + +/* 逆初始置换表IP^-1 */ +static HGByte IP_1_Table[64] = +{ + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, + 32, 0, 40, 8, 48, 16, 56, 24 +}; + +/* 扩充置换表E */ +static HGByte E_Table[48] = +{ + 31, 0, 1, 2, 3, 4, + 3, 4, 5, 6, 7, 8, + 7, 8, 9,10, 11, 12, + 11, 12, 13, 14, 15, 16, + 15, 16, 17, 18, 19, 20, + 19, 20, 21, 22, 23, 24, + 23, 24, 25, 26, 27, 28, + 27, 28, 29, 30, 31, 0 +}; + +/* 置换函数P */ +static HGByte P_Table[32] = +{ + 15, 6, 19, 20, 28, 11, 27, 16, + 0, 14, 22, 25, 4, 17, 30, 9, + 1, 7, 23, 13, 31, 26, 2, 8, + 18, 12, 29, 5, 21, 10, 3, 24 +}; + +/* S盒 */ +static HGByte S[8][4][16] = +{ + /* S1 */ + 14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7, + 0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8, + 4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0, + 15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13, + + /* S2 */ + 15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10, + 3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5, + 0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15, + 13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9, + + /* S3 */ + 10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8, + 13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1, + 13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7, + 1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12, + + /* S4 */ + 7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15, + 13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9, + 10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4, + 3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14, + + /* S5 */ + 2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9, + 14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6, + 4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14, + 11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3, + + /* S6 */ + 12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11, + 10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8, + 9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6, + 4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13, + + /* S7 */ + 4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1, + 13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6, + 1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2, + 6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12, + + /* S8 */ + 13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7, + 1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2, + 7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8, + 2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11 +}; + +/* 置换选择1 */ +static HGByte PC_1[56] = +{ + 56,48,40,32,24,16,8, + 0,57,49,41,33,25,17, + 9,1,58,50,42,34,26, + 18,10,2,59,51,43,35, + 62,54,46,38,30,22,14, + 6,61,53,45,37,29,21, + 13,5,60,52,44,36,28, + 20,12,4,27,19,11,3 +}; + +/* 置换选择2 */ +static HGByte PC_2[48] = +{ + 13,16,10,23,0,4,2,27, + 14,5,20,9,22,18,11,3, + 25,7,15,6,26,19,12,1, + 40,51,30,36,46,54,29,39, + 50,44,32,46,43,48,38,55, + 33,52,45,41,49,35,28,31 +}; + +/* 对左移次数的规定 */ +static HGByte MOVE_TIMES[16] = { 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 }; + + +static int ByteToBit8(HGByte ch, HGByte bit[8]) +{ + for (int cnt = 0; cnt < 8; cnt++) + { + *(bit + cnt) = (ch >> cnt) & 1; + } + + return 0; +} + +static int Bit8ToByte(const HGByte bit[8], HGByte* ch) +{ + if (NULL == ch) + return -1; + + *ch = 0; + for (int cnt = 0; cnt < 8; cnt++) + { + *ch |= *(bit + cnt) << cnt; + } + + return 0; +} + +static int Byte8ToBit64(const HGByte ch[8], HGByte bit[64]) +{ + for (int cnt = 0; cnt < 8; cnt++) + { + ByteToBit8(*(ch + cnt), bit + (cnt << 3)); + } + + return 0; +} + +static int Bit64ToByte8(HGByte bit[64], HGByte ch[8]) +{ + memset(ch, 0, 8); + for (int cnt = 0; cnt < 8; cnt++) + { + Bit8ToByte(bit + (cnt << 3), ch + cnt); + } + + return 0; +} + +/* 密钥置换1 */ +static int DES_PC1_Transform(HGByte key[64], HGByte tempbts[56]) +{ + for (int cnt = 0; cnt < 56; cnt++) + { + tempbts[cnt] = key[PC_1[cnt]]; + } + + return 0; +} + +/* 密钥置换2 */ +static int DES_PC2_Transform(HGByte key[56], HGByte tempbts[48]) +{ + for (int cnt = 0; cnt < 48; cnt++) + { + tempbts[cnt] = key[PC_2[cnt]]; + } + + return 0; +} + +/* 循环左移 */ +static int DES_ROL(HGByte data[56], int time) +{ + HGByte temp[56]; + HGByte temp2[28]; + + /* 保存将要循环移动到右边的位 */ + memcpy(temp, data, time); + memcpy(temp + time, data + 28, time); + + /* 前28位移动 */ + //memcpy(data, data + time, 28 - time); + memcpy(temp2, data + time, 28 - time); + memcpy(data, temp2, 28 - time); + memcpy(data + 28 - time, temp, time); + + /* 后28位移动 */ + //memcpy(data + 28, data + 28 + time, 28 - time); + memcpy(temp2, data + 28 + time, 28 - time); + memcpy(data + 28, temp2, 28 - time); + memcpy(data + 56 - time, temp + time, time); + + return 0; +} + +/* 生成子密钥 */ +static int DES_MakeSubKeys(HGByte key[64], HGByte subKeys[16][48]) +{ + HGByte temp[56]; + DES_PC1_Transform(key, temp); /* PC1置换 */ + + for (int cnt = 0; cnt < 16; cnt++) + { + /* 16轮跌代,产生16个子密钥 */ + DES_ROL(temp, MOVE_TIMES[cnt]); /* 循环左移 */ + DES_PC2_Transform(temp, subKeys[cnt]); /* PC2置换,产生子密钥 */ + } + + return 0; +} + +/* IP置换 */ +static int DES_IP_Transform(HGByte data[64]) +{ + HGByte temp[64]; + for (int cnt = 0; cnt < 64; cnt++) + { + temp[cnt] = data[IP_Table[cnt]]; + } + + memcpy(data, temp, 64); + return 0; +} + +/* IP逆置换 */ +static int DES_IP_1_Transform(HGByte data[64]) +{ + HGByte temp[64]; + for (int cnt = 0; cnt < 64; cnt++) + { + temp[cnt] = data[IP_1_Table[cnt]]; + } + + memcpy(data, temp, 64); + return 0; +} + +/* 扩展置换 */ +static int DES_E_Transform(HGByte data[48]) +{ + HGByte temp[48]; + for (int cnt = 0; cnt < 48; cnt++) + { + temp[cnt] = data[E_Table[cnt]]; + } + + memcpy(data, temp, 48); + return 0; +} + +/* P置换 */ +static int DES_P_Transform(HGByte data[32]) +{ + HGByte temp[32]; + for (int cnt = 0; cnt < 32; cnt++) + { + temp[cnt] = data[P_Table[cnt]]; + } + + memcpy(data, temp, 32); + return 0; +} + +/* 异或 */ +static int DES_XOR(HGByte R[48], HGByte L[48], int count) +{ + for (int cnt = 0; cnt < count; cnt++) + { + R[cnt] ^= L[cnt]; + } + + return 0; +} + +/* S盒置换 */ +static int DES_SBOX(HGByte data[48]) +{ + for (int cnt = 0; cnt < 8; cnt++) + { + int cur1 = cnt * 6; + int cur2 = cnt << 2; + + /* 计算在S盒中的行与列 */ + int line = (data[cur1] << 1) + data[cur1 + 5]; + int row = (data[cur1 + 1] << 3) + (data[cur1 + 2] << 2) + (data[cur1 + 3] << 1) + data[cur1 + 4]; + int output = S[cnt][line][row]; + + /* 化为2进制 */ + data[cur2] = (output & 0X08) >> 3; + data[cur2 + 1] = (output & 0X04) >> 2; + data[cur2 + 2] = (output & 0X02) >> 1; + data[cur2 + 3] = output & 0x01; + } + + return 0; +} + +/* 交换 */ +static int DES_Swap(HGByte left[32], HGByte right[32]) +{ + HGByte temp[32]; + memcpy(temp, left, 32); + memcpy(left, right, 32); + memcpy(right, temp, 32); + + return 0; +} + +/* 加密单个分组 */ +static int DES_EncryptBlock(HGByte plainBlock[8], HGByte subKeys[16][48], HGByte cipherBlock[8]) +{ + HGByte plainBits[64]; + HGByte copyRight[48]; + + Byte8ToBit64(plainBlock, plainBits); + /* 初始置换(IP置换) */ + DES_IP_Transform(plainBits); + + /* 16轮迭代 */ + for (int cnt = 0; cnt < 16; cnt++) + { + memcpy(copyRight, plainBits + 32, 32); + + /* 将右半部分进行扩展置换,从32位扩展到48位 */ + DES_E_Transform(copyRight); + /* 将右半部分与子密钥进行异或操作 */ + DES_XOR(copyRight, subKeys[cnt], 48); + /* 异或结果进入S盒,输出32位结果 */ + DES_SBOX(copyRight); + /* P置换 */ + DES_P_Transform(copyRight); + /* 将明文左半部分与右半部分进行异或 */ + DES_XOR(plainBits, copyRight, 32); + + if (cnt != 15) + { + /* 最终完成左右部的交换 */ + DES_Swap(plainBits, plainBits + 32); + } + } + + /* 逆初始置换(IP^1置换) */ + DES_IP_1_Transform(plainBits); + Bit64ToByte8(plainBits, cipherBlock); + return 0; +} + + +/* 解密单个分组 */ + +static int DES_DecryptBlock(HGByte cipherBlock[8], HGByte subKeys[16][48], HGByte plainBlock[8]) +{ + HGByte cipherBits[64]; + HGByte copyRight[48]; + + Byte8ToBit64(cipherBlock, cipherBits); + /* 初始置换(IP置换) */ + DES_IP_Transform(cipherBits); + + /* 16轮迭代 */ + for (int cnt = 15; cnt >= 0; cnt--) + { + memcpy(copyRight, cipherBits + 32, 32); + + /* 将右半部分进行扩展置换,从32位扩展到48位 */ + DES_E_Transform(copyRight); + /* 将右半部分与子密钥进行异或操作 */ + DES_XOR(copyRight, subKeys[cnt], 48); + /* 异或结果进入S盒,输出32位结果 */ + DES_SBOX(copyRight); + /* P置换 */ + DES_P_Transform(copyRight); + /* 将明文左半部分与右半部分进行异或 */ + DES_XOR(cipherBits, copyRight, 32); + + if (cnt != 0) + { + /* 最终完成左右部的交换 */ + DES_Swap(cipherBits, cipherBits + 32); + } + } + + /* 逆初始置换(IP^1置换) */ + DES_IP_1_Transform(cipherBits); + Bit64ToByte8(cipherBits, plainBlock); + return 0; +} + + +HGResult HGAPI HGBase_DesEncrypt(HGByte* data, HGUInt size, const HGByte* key) +{ + if (NULL == data || 0 == size || 0 != size % 8 || NULL == key) + { + return HGBASE_ERR_INVALIDARG; + } + + HGByte bKey[64]; + HGByte subKeys[16][48]; + HGByte plainBlock[8]; + + /* 将密钥转换为二进制流 */ + Byte8ToBit64(key, bKey); + /* 生成子密钥 */ + DES_MakeSubKeys(bKey, subKeys); + + HGByte* p = data; + HGByte* pe = data + size; + while (p < pe) + { + memcpy(plainBlock, p, 8); + DES_EncryptBlock(plainBlock, subKeys, p); + p += 8; + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_DesDecrypt(HGByte* data, HGUInt size, const HGByte* key) +{ + if (NULL == data || 0 == size || 0 != size % 8 || NULL == key) + { + return HGBASE_ERR_INVALIDARG; + } + + HGByte bKey[64]; + HGByte subKeys[16][48]; + HGByte cipherBlock[8]; + + /* 将密钥转换为二进制流 */ + Byte8ToBit64(key, bKey); + /* 生成子密钥 */ + DES_MakeSubKeys(bKey, subKeys); + + HGByte* p = data; + HGByte* pe = data + size; + while (p < pe) + { + memcpy(cipherBlock, p, 8); + DES_DecryptBlock(cipherBlock, subKeys, p); + p += 8; + } + + return HGBASE_ERR_OK; +} \ No newline at end of file diff --git a/app/modules/base/HGDes.h b/app/modules/base/HGDes.h new file mode 100644 index 0000000..f246065 --- /dev/null +++ b/app/modules/base/HGDes.h @@ -0,0 +1,27 @@ +#ifndef __HGDES_H__ +#define __HGDES_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* DES加密 +* 参数: +* 1) data: in, out, 明文 +* 2) size: in, 明文尺寸, 必须是8的倍数 +* 3) key: in, 加密密钥, 为8字节数组 +* 说明: +* 1) 加密后的密文会覆盖明文,如果需要保留明文,需要提前保存 +*/ +HGEXPORT HGResult HGAPI HGBase_DesEncrypt(HGByte* data, HGUInt size, const HGByte* key); + +/* DES解密 +* 参数: +* 1) data: in, out, 密文 +* 2) size: in, 密文尺寸, 必须是8的倍数 +* 3) key: in, 解密密钥, 为8字节数组 +* 说明: +* 1) 解密后的明文会覆盖密文,如果需要保留密文,需要提前保存 +*/ +HGEXPORT HGResult HGAPI HGBase_DesDecrypt(HGByte* data, HGUInt size, const HGByte* key); + +#endif /* __HGDES_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGDll.cpp b/app/modules/base/HGDll.cpp new file mode 100644 index 0000000..45e59a7 --- /dev/null +++ b/app/modules/base/HGDll.cpp @@ -0,0 +1,94 @@ +#include "HGDll.h" +#include "HGInc.h" +#include "HGInfo.h" +#if !defined(HG_CMP_MSC) +#include +#endif + +struct HGDllImpl +{ + HGDllImpl() + { + m_hDll = NULL; + } + + ~HGDllImpl() + { + if (NULL != m_hDll) + { +#if !defined(HG_CMP_MSC) + dlclose(m_hDll); +#else + FreeLibrary(m_hDll); +#endif + m_hDll = NULL; + } + } + +#if !defined(HG_CMP_MSC) + void* m_hDll; +#else + HMODULE m_hDll; +#endif +}; + +HGResult HGAPI HGBase_CreateDll(const HGChar* fileName, HGDll* dll) +{ + if (NULL == fileName || NULL == dll) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + void* hDll = dlopen(fileName, RTLD_LAZY); + if (NULL == hDll) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGBase_CreateDll: dlopen fail, %s dlerror=%s", fileName, dlerror()); + return HGBASE_ERR_LOADLIBRARY; + } +#else + HMODULE hDll = LoadLibraryExA((const char *)fileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (NULL == hDll) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGBase_CreateDll: LoadLibraryExA fail, %s GetLastError=%u", fileName, GetLastError()); + return HGBASE_ERR_LOADLIBRARY; + } +#endif + HGDllImpl* dllImpl = new HGDllImpl; + dllImpl->m_hDll = hDll; + *dll = (HGDll)dllImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_DestroyDll(HGDll dll) +{ + if (NULL == dll) + { + return HGBASE_ERR_INVALIDARG; + } + + HGDllImpl* dllImpl = (HGDllImpl*)dll; + delete dllImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetDllProcAddress(HGDll dll, const HGChar* symbol, HGPointer* func) +{ + if (NULL == dll || NULL == symbol || NULL == func) + { + return HGBASE_ERR_INVALIDARG; + } + + HGDllImpl* dllImpl = (HGDllImpl*)dll; +#if !defined(HG_CMP_MSC) + *func = dlsym(dllImpl->m_hDll, symbol); +#else + * func = GetProcAddress(dllImpl->m_hDll, (const char *)symbol); +#endif + if (NULL == *func) + { + return HGBASE_ERR_FAIL; + } + + return HGBASE_ERR_OK; +} diff --git a/app/modules/base/HGDll.h b/app/modules/base/HGDll.h new file mode 100644 index 0000000..00e78d1 --- /dev/null +++ b/app/modules/base/HGDll.h @@ -0,0 +1,35 @@ +#ifndef __HGDLL_H__ +#define __HGDLL_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGDll); + +/* 加载DLL +* 参数: +* 1) fileName: in, dll/so文件路径, 可以是绝对路径或相对路径 +* 2) dll: out, DLL句柄 +* 说明: +* 1) 在windows系统上, fileName需要是GBK编码 +* 2) 在linux系统上, fileName需要是UTF8编码 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateDll(const HGChar* fileName, HGDll* dll); + +/* 销毁DLL +* 参数: +* 1) dll: in, DLL句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_DestroyDll(HGDll dll); + +/* 查找函数地址 +* 参数: +* 1) dll: in, DLL句柄 +* 2) symbol: in, 函数名 +* 3) func: out, 函数地址 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_GetDllProcAddress(HGDll dll, const HGChar* symbol, HGPointer* func); + +#endif /* __HGDLL_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGEvent.cpp b/app/modules/base/HGEvent.cpp new file mode 100644 index 0000000..91374c6 --- /dev/null +++ b/app/modules/base/HGEvent.cpp @@ -0,0 +1,238 @@ +#include "HGEvent.h" +#include "HGInc.h" + +#if !defined(HG_CMP_MSC) +struct event_t +{ + HGBool state; + HGBool manual_reset; + pthread_mutex_t mutex; + pthread_cond_t cond; +}; +#endif + +HGResult HGAPI HGBase_CreateEvent(HGBool manualReset, HGBool initState, HGEvent* event) +{ + if (NULL == event) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + event_t* hEvent = new event_t; + + hEvent->state = initState; + hEvent->manual_reset = manualReset; + if (0 != pthread_mutex_init(&hEvent->mutex, NULL)) + { + delete hEvent; + return HGBASE_ERR_FAIL; + } + if (0 != pthread_cond_init(&hEvent->cond, NULL)) + { + pthread_mutex_destroy(&hEvent->mutex); + delete hEvent; + return HGBASE_ERR_FAIL; + } + *event = (HGEvent)hEvent; +#else + HANDLE hEvent = CreateEventW(NULL, (BOOL)manualReset, (BOOL)initState, NULL); + *event = (HGEvent)hEvent; +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_DestroyEvent(HGEvent event) +{ + if (NULL == event) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + event_t* hEvent = (event_t*)event; + pthread_cond_destroy(&hEvent->cond); + pthread_mutex_destroy(&hEvent->mutex); + delete hEvent; +#else + HANDLE hEvent = (HANDLE)event; + CloseHandle(hEvent); +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_WaitEvent(HGEvent event) +{ + if (NULL == event) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + event_t* hEvent = (event_t*)event; + if (0 != pthread_mutex_lock(&hEvent->mutex)) + { + return HGBASE_ERR_FAIL; + } + while (!hEvent->state) + { + if (0 != pthread_cond_wait(&hEvent->cond, &hEvent->mutex)) + { + pthread_mutex_unlock(&hEvent->mutex); + return HGBASE_ERR_FAIL; + } + } + if (!hEvent->manual_reset) + { + hEvent->state = HGFALSE; + } + if (0 != pthread_mutex_unlock(&hEvent->mutex)) + { + return HGBASE_ERR_FAIL; + } +#else + HANDLE hEvent = (HANDLE)event; + DWORD ret = WaitForSingleObject(hEvent, INFINITE); + if (WAIT_OBJECT_0 != ret) + { + return HGBASE_ERR_FAIL; + } +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_WaitEventTimeout(HGEvent event, HGUInt milliseconds) +{ + if (NULL == event) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + struct timespec abstime; + struct timeval tv; + gettimeofday(&tv, NULL); + abstime.tv_sec = tv.tv_sec + milliseconds / 1000; + abstime.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000; + if (abstime.tv_nsec >= 1000000000) + { + abstime.tv_nsec -= 1000000000; + abstime.tv_sec++; + } + + int rc = 0; + event_t* hEvent = (event_t*)event; + if (pthread_mutex_lock(&hEvent->mutex) != 0) + { + return HGBASE_ERR_FAIL; + } + while (!hEvent->state) + { + rc = pthread_cond_timedwait(&hEvent->cond, &hEvent->mutex, &abstime); + if (0 != rc) + { + if (rc == ETIMEDOUT) + break; + + pthread_mutex_unlock(&hEvent->mutex); + return HGBASE_ERR_FAIL; + } + } + if (rc == 0 && !hEvent->manual_reset) + { + hEvent->state = HGFALSE; + } + if (pthread_mutex_unlock(&hEvent->mutex) != 0) + { + return HGBASE_ERR_FAIL; + } + if (rc == ETIMEDOUT) + { + return HGBASE_ERR_TIMEOUT; + } + return HGBASE_ERR_OK; +#else + HANDLE hEvent = (HANDLE)event; + DWORD ret = WaitForSingleObject(hEvent, milliseconds); + if (WAIT_OBJECT_0 == ret) + { + return HGBASE_ERR_OK; + } + else if (WAIT_TIMEOUT == ret) + { + return HGBASE_ERR_TIMEOUT; + } + return HGBASE_ERR_FAIL; +#endif +} + +HGResult HGAPI HGBase_SetEvent(HGEvent event) +{ + if (NULL == event) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + event_t* hEvent = (event_t*)event; + if (0 != pthread_mutex_lock(&hEvent->mutex)) + { + return HGBASE_ERR_FAIL; + } + + hEvent->state = HGTRUE; + if (hEvent->manual_reset) + { + if (0 != pthread_cond_broadcast(&hEvent->cond)) + { + pthread_mutex_unlock(&hEvent->mutex); + return HGBASE_ERR_FAIL; + } + } + else + { + if (0 != pthread_cond_signal(&hEvent->cond)) + { + pthread_mutex_unlock(&hEvent->mutex); + return HGBASE_ERR_FAIL; + } + } + + if (0 != pthread_mutex_unlock(&hEvent->mutex)) + { + return HGBASE_ERR_FAIL; + } + return HGBASE_ERR_OK; +#else + HANDLE hEvent = (HANDLE)event; + SetEvent(hEvent); + return HGBASE_ERR_OK; +#endif +} + +HGResult HGAPI HGBase_ResetEvent(HGEvent event) +{ + if (NULL == event) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + event_t* hEvent = (event_t*)event; + if (0 != pthread_mutex_lock(&hEvent->mutex)) + { + return HGBASE_ERR_FAIL; + } + + hEvent->state = HGFALSE; + if (0 != pthread_mutex_unlock(&hEvent->mutex)) + { + return HGBASE_ERR_FAIL; + } + return HGBASE_ERR_OK; +#else + HANDLE hEvent = (HANDLE)event; + ResetEvent(hEvent); + return HGBASE_ERR_OK; +#endif +} diff --git a/app/modules/base/HGEvent.h b/app/modules/base/HGEvent.h new file mode 100644 index 0000000..205afc5 --- /dev/null +++ b/app/modules/base/HGEvent.h @@ -0,0 +1,60 @@ +#ifndef __HGEVENT_H__ +#define __HGEVENT_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGEvent); + +/* 创建事件 +* 参数: +* 1) manualReset: in, 是否手动设置 +* 2) initState: in, 初始化时是否有信号 +* 3) event: out, 事件句柄 +* 说明: +* 1) 当manualReset为HGTRUE时, HGBase_WaitEvent和HGBase_WaitEventTimeout调用后, 事件仍然为有信号 +* 2) 当manualReset为HGFALSE时, HGBase_WaitEvent和HGBase_WaitEventTimeout调用后, 事件为无信号 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateEvent(HGBool manualReset, HGBool initState, HGEvent* event); + +/* 销毁事件 +* 参数: +* 1) event: in, 事件句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_DestroyEvent(HGEvent event); + +/* 无限等待事件 +* 参数: +* 1) event: in, 事件句柄 +* 说明: +* 1) 如果创建时的manualReset为HGTRUE, 返回前不会将事件置为无信号;否则,返回前会将事件置为无信号 +*/ +HGEXPORT HGResult HGAPI HGBase_WaitEvent(HGEvent event); + +/* 等待事件, 带超时时间 +* 参数: +* 1) event: in, 事件句柄 +* 2) milliseconds: in, 超时时间, 毫秒 +* 说明: +* 1) 在milliseconds时间内如果事件有信号,立即返回 +* 2) 如果一直无信号, 在milliseconds毫秒后也立即返回, 返回值为HGBASE_ERR_WAIT_TIMEOUT +* 3) 如果创建时的manualReset为HGTRUE, 返回前不会将事件置为无信号;否则,返回前会将事件置为无信号 +*/ +HGEXPORT HGResult HGAPI HGBase_WaitEventTimeout(HGEvent event, HGUInt milliseconds); + +/* 使事件有信号 +* 参数: +* 1) event: in, 事件句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_SetEvent(HGEvent event); + +/* 使事件无信号 +* 参数: +* 1) event: in, 事件句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_ResetEvent(HGEvent event); + +#endif /* __HGEVENT_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGImage.cpp b/app/modules/base/HGImage.cpp new file mode 100644 index 0000000..dd9686f --- /dev/null +++ b/app/modules/base/HGImage.cpp @@ -0,0 +1,3189 @@ +#include "HGImage.h" +#include "HGInc.h" +#if defined(HG_CMP_MSC) +#include +#include +#endif + +struct HGImageImpl +{ + HGImageImpl() + { +#if defined(HG_CMP_MSC) + m_hBmp = NULL; +#endif + m_data = NULL; + m_size = 0; + m_alloc = HGFALSE; + + m_width = 0; + m_height = 0; + m_type = 0; + m_widthStep = 0; + m_origin = 0; + + m_left = 0; + m_top = 0; + m_right = 0; + m_bottom = 0; + m_xDpi = 96; + m_yDpi = 96; + } + + ~HGImageImpl() + { + if (m_alloc) + { + free(m_data); + m_data = NULL; + } +#if defined(HG_CMP_MSC) + if (NULL != m_hBmp) + { + DeleteObject(m_hBmp); + m_hBmp = NULL; + } +#endif + } + +#if defined(HG_CMP_MSC) + HBITMAP m_hBmp; +#endif + HGByte* m_data; + HGUSize m_size; + HGBool m_alloc; + + HGUInt m_width; + HGUInt m_height; + HGUInt m_type; + HGUInt m_widthStep; + HGUInt m_origin; + + HGUInt m_left; + HGUInt m_top; + HGUInt m_right; + HGUInt m_bottom; + HGUInt m_xDpi; + HGUInt m_yDpi; +}; + +#if defined(HG_CMP_MSC) +static HBITMAP CreateHBITMAP(HGUInt width, HGUInt height, HGUInt type, HGUInt origin, + HGUInt xDpi, HGUInt yDpi, HGByte** data) +{ + BYTE bmi[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)] = { 0 }; + BITMAPINFOHEADER* pbmihdr = (BITMAPINFOHEADER*)bmi; + pbmihdr->biSize = sizeof(BITMAPINFOHEADER); + pbmihdr->biWidth = (LONG)width; + pbmihdr->biHeight = (HGBASE_IMGORIGIN_BOTTOM == origin) ? (LONG)height : -(LONG)height; + pbmihdr->biPlanes = 1; + pbmihdr->biCompression = BI_RGB; + pbmihdr->biXPelsPerMeter = (LONG)(xDpi * 39.37); + pbmihdr->biYPelsPerMeter = (LONG)(yDpi * 39.37); + + if (HGBASE_IMGTYPE_BGR == type) + { + pbmihdr->biBitCount = 24; + } + else if (HGBASE_IMGTYPE_BGRA == type) + { + pbmihdr->biBitCount = 32; + } + else if (HGBASE_IMGTYPE_GRAY == type) + { + pbmihdr->biBitCount = 8; + + RGBQUAD* clr = (RGBQUAD*)(pbmihdr + 1); + for (int i = 0; i < 256; ++i) + { + clr[i].rgbRed = i; + clr[i].rgbGreen = i; + clr[i].rgbBlue = i; + } + } + else if (HGBASE_IMGTYPE_BINARY == type) + { + pbmihdr->biBitCount = 1; + + RGBQUAD* clr = (RGBQUAD*)(pbmihdr + 1); + for (int i = 0; i < 2; ++i) + { + clr[i].rgbRed = i * 255; + clr[i].rgbGreen = i * 255; + clr[i].rgbBlue = i * 255; + } + } + else + { + return NULL; + } + + void* pBits = NULL; + HBITMAP hBmp = CreateDIBSection(NULL, (BITMAPINFO*)bmi, DIB_RGB_COLORS, &pBits, NULL, 0); + if (NULL == hBmp) + { + return NULL; + } + + *data = (HGByte*)pBits; + return hBmp; +} +#endif + +HGResult HGAPI HGBase_CreateImage(HGUInt width, HGUInt height, HGUInt type, HGUInt origin, HGImage* image) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == width || 0 == height || origin < HGBASE_IMGORIGIN_TOP || origin > HGBASE_IMGORIGIN_BOTTOM) + { + return HGBASE_ERR_INVALIDARG; + } + + HGUInt bpp = 0; + if (HGBASE_IMGTYPE_BINARY == type) + bpp = 1; + else if (HGBASE_IMGTYPE_GRAY == type) + bpp = 8; + else if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + bpp = 24; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + bpp = 32; + if (0 == bpp) + { + return HGBASE_ERR_INVALIDARG; + } + + // 每行4字节对齐 + HGUInt widthStep = ((width * bpp + 31) & ~31) >> 3; + HGUSize size = (HGUSize)widthStep * (HGUSize)height; + + HGByte* data = NULL; + HGBool alloc = HGFALSE; +#if defined(HG_CMP_MSC) + HBITMAP hBmp = NULL; + if (HGBASE_IMGTYPE_RGB == type || HGBASE_IMGTYPE_RGBA == type) + { + data = (HGByte*)malloc(size); + if (NULL == data) + return HGBASE_ERR_OUTOFMEMORY; + else + alloc = HGTRUE; + } + else + { + hBmp = CreateHBITMAP(width, height, type, origin, 96, 96, &data); + if (NULL == hBmp) + return HGBASE_ERR_OUTOFMEMORY; + else + assert(NULL != data); + } +#else + data = (HGByte*)malloc(size); + if (NULL == data) + return HGBASE_ERR_OUTOFMEMORY; + else + alloc = HGTRUE; +#endif + + HGImageImpl* imageImpl = new HGImageImpl; +#if defined(HG_CMP_MSC) + imageImpl->m_hBmp = hBmp; +#endif + imageImpl->m_data = data; + imageImpl->m_size = size; + imageImpl->m_alloc = alloc; + + imageImpl->m_width = width; + imageImpl->m_height = height; + imageImpl->m_type = type; + imageImpl->m_widthStep = widthStep; + imageImpl->m_origin = origin; + + imageImpl->m_left = 0; + imageImpl->m_top = 0; + imageImpl->m_right = imageImpl->m_width; + imageImpl->m_bottom = imageImpl->m_height; + imageImpl->m_xDpi = 96; + imageImpl->m_yDpi = 96; + + *image = (HGImage)imageImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CreateImageWithData(HGByte* data, const HGImageInfo* info, HGImage* image) +{ + if (NULL == data || NULL == info || NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == info->width || 0 == info->height || info->origin < HGBASE_IMGORIGIN_TOP + || info->origin > HGBASE_IMGORIGIN_BOTTOM) + { + return HGBASE_ERR_INVALIDARG; + } + + HGUInt bpp = 0; + if (HGBASE_IMGTYPE_BINARY == info->type) + bpp = 1; + else if (HGBASE_IMGTYPE_GRAY == info->type) + bpp = 8; + else if (HGBASE_IMGTYPE_BGR == info->type || HGBASE_IMGTYPE_RGB == info->type) + bpp = 24; + else if (HGBASE_IMGTYPE_BGRA == info->type || HGBASE_IMGTYPE_RGBA == info->type) + bpp = 32; + if (0 == bpp) + { + return HGBASE_ERR_INVALIDARG; + } + + // info->widthStep必须合法 + HGUInt lineSize = ((info->width * bpp + 7) & ~7) >> 3; + if (info->widthStep < lineSize) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = new HGImageImpl; +#if defined(HG_CMP_MSC) + imageImpl->m_hBmp = NULL; +#endif + imageImpl->m_data = data; + imageImpl->m_size = (HGUSize)info->widthStep * (HGUSize)info->height; + imageImpl->m_alloc = HGFALSE; + + imageImpl->m_width = info->width; + imageImpl->m_height = info->height; + imageImpl->m_type = info->type; + imageImpl->m_widthStep = info->widthStep; + imageImpl->m_origin = info->origin; + + imageImpl->m_left = 0; + imageImpl->m_top = 0; + imageImpl->m_right = imageImpl->m_width; + imageImpl->m_bottom = imageImpl->m_height; + imageImpl->m_xDpi = 96; + imageImpl->m_yDpi = 96; + + *image = (HGImage)imageImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CreateImageFromData(HGByte* data, const HGImageInfo* info, const HGImageRoi* roi, + HGUInt type, HGUInt origin, HGImage* image) +{ + HGImage srcImage = NULL; + HGResult ret = HGBase_CreateImageWithData(data, info, &srcImage); + if (HGBASE_ERR_OK != ret) + return ret; + + if (NULL != roi) + { + ret = HGBase_SetImageROI(srcImage, roi); + if (HGBASE_ERR_OK != ret) + { + HGBase_DestroyImage(srcImage); + return ret; + } + } + + ret = HGBase_CloneImage(srcImage, type, origin, image); + HGBase_DestroyImage(srcImage); + return ret; +} + +#if defined(HG_CMP_MSC) + +static HGUInt GetType(HBITMAP hBmp) +{ + assert(NULL != hBmp); + HGUInt type = HGBASE_IMGTYPE_BGR; + + DIBSECTION dib; + int ret = GetObject(hBmp, sizeof(DIBSECTION), &dib); + assert(sizeof(DIBSECTION) == ret); + + RGBQUAD colorTable[256]; + HDC hMem = CreateCompatibleDC(NULL); + HBITMAP hOldBmp = (HBITMAP)SelectObject(hMem, hBmp); + UINT colorCount = GetDIBColorTable(hMem, 0, 256, colorTable); + SelectObject(hMem, hOldBmp); + DeleteDC(hMem); + + if (1 == dib.dsBmih.biBitCount || 4 == dib.dsBmih.biBitCount + || 8 == dib.dsBmih.biBitCount) + { + assert(colorCount > 0); + + BOOL bGray = TRUE; + BOOL bBinary = TRUE; + for (UINT i = 0; i < colorCount; ++i) + { + BYTE red = colorTable[i].rgbRed; + BYTE green = colorTable[i].rgbGreen; + BYTE blue = colorTable[i].rgbBlue; + + if (red != green || red != blue || green != blue) + { + bGray = FALSE; + bBinary = FALSE; + break; + } + + if (red != 0 && red != 255) + { + bBinary = FALSE; + } + } + + if (bBinary) + type = HGBASE_IMGTYPE_BINARY; + else if (bGray) + type = HGBASE_IMGTYPE_GRAY; + } + else if (32 == dib.dsBmih.biBitCount) + { + type = HGBASE_IMGTYPE_BGRA; + } + + return type; +} + +HGResult HGAPI HGBase_CreateImageFromHBITMAP(HBITMAP hBmp, const HGImageRoi* roi, + HGUInt type, HGUInt origin, HGImage* image) +{ + if (NULL == hBmp || NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + DIBSECTION dib; + if (sizeof(DIBSECTION) != GetObject(hBmp, sizeof(DIBSECTION), &dib)) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGImageRoi roi2 = { 0, 0, (HGUInt)dib.dsBm.bmWidth, (HGUInt)dib.dsBm.bmHeight }; + if (NULL != roi) + { + if (roi->left >= roi->right || roi->top >= roi->bottom + || roi->right > (HGUInt)dib.dsBm.bmWidth || roi->bottom > (HGUInt)dib.dsBm.bmHeight) + { + return HGBASE_ERR_INVALIDARG; + } + + memcpy(&roi2, roi, sizeof(HGImageRoi)); + } + + if (0 == type) + { + type = GetType(hBmp); + } + + HGResult ret = HGBase_CreateImage(roi2.right - roi2.left, roi2.bottom - roi2.top, type, origin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HBITMAP hBmp2 = NULL; + HGBase_GetHBITMAPOfImage(*image, &hBmp2); + if (NULL != hBmp2) + { + HDC hMem = CreateCompatibleDC(NULL); + HBITMAP hOldBmp = (HBITMAP)SelectObject(hMem, hBmp); + HDC hMem2 = CreateCompatibleDC(hMem); + HBITMAP hOldBmp2 = (HBITMAP)SelectObject(hMem2, hBmp2); + BitBlt(hMem2, 0, 0, roi2.right - roi2.left, roi2.bottom - roi2.top, hMem, roi2.left, roi2.top, SRCCOPY); + SelectObject(hMem2, hOldBmp2); + DeleteDC(hMem2); + SelectObject(hMem, hOldBmp); + DeleteDC(hMem); + ret = HGBASE_ERR_OK; + } + else + { + HGUInt type2 = type; + if (HGBASE_IMGTYPE_RGB == type) + type2 = HGBASE_IMGTYPE_BGR; + else if (HGBASE_IMGTYPE_RGBA == type) + type2 = HGBASE_IMGTYPE_BGRA; + + HGImage image2 = NULL; + ret = HGBase_CreateImageFromHBITMAP(hBmp, roi, type2, origin, &image2); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(image2, *image); + HGBase_DestroyImage(image2); + } + + if (HGBASE_ERR_OK != ret) + HGBase_DestroyImage(*image); + } + + if (HGBASE_ERR_OK == ret) + { + HGUInt xDpi = (HGUInt)(dib.dsBmih.biXPelsPerMeter / 39.37); + HGUInt yDpi = (HGUInt)(dib.dsBmih.biYPelsPerMeter / 39.37); + HGBase_SetImageDpi(*image, xDpi, yDpi); + } + + return ret; +} + +static HGUInt GetType(Gdiplus::Image* pImage) +{ + assert(NULL != pImage); + HGUInt type = HGBASE_IMGTYPE_BGR; + + Gdiplus::PixelFormat pixFmt = pImage->GetPixelFormat(); + if (PixelFormat16bppGrayScale == pixFmt) + { + type = HGBASE_IMGTYPE_GRAY; + } + else if (Gdiplus::IsIndexedPixelFormat(pixFmt)) + { + UINT nPaletteSize = pImage->GetPaletteSize(); + Gdiplus::ColorPalette* pPalette = (Gdiplus::ColorPalette*)malloc(nPaletteSize); + if (NULL != pPalette) + { + pImage->GetPalette(pPalette, nPaletteSize); + + BOOL bGray = TRUE; + BOOL bBinary = TRUE; + for (UINT i = 0; i < pPalette->Count; ++i) + { + Gdiplus::ARGB color = pPalette->Entries[i]; + BYTE red = (BYTE)((color >> RED_SHIFT) & 0xFF); + BYTE green = (BYTE)((color >> GREEN_SHIFT) & 0xFF); + BYTE blue = (BYTE)((color >> BLUE_SHIFT) & 0xFF); + + if (red != green || red != blue || green != blue) + { + bGray = FALSE; + bBinary = FALSE; + break; + } + + if (red != 0 && red != 255) + { + bBinary = FALSE; + } + } + + if (bBinary) + type = HGBASE_IMGTYPE_BINARY; + else if (bGray) + type = HGBASE_IMGTYPE_GRAY; + + free(pPalette); + } + } + else if (Gdiplus::IsAlphaPixelFormat(pixFmt)) + { + type = HGBASE_IMGTYPE_BGRA; + } + + return type; +} + +static HGResult LoadGdiImage(Gdiplus::Image* pImage, const HGImageRoi* roi, HGUInt type, HGUInt origin, HGImage* image) +{ + assert(NULL != pImage && NULL != image); + + HGImageRoi roi2 = { 0, 0, pImage->GetWidth(), pImage->GetHeight() }; + if (NULL != roi) + { + if (roi->left >= roi->right || roi->top >= roi->bottom + || roi->right > pImage->GetWidth() || roi->bottom > pImage->GetHeight()) + { + return HGBASE_ERR_INVALIDARG; + } + + memcpy(&roi2, roi, sizeof(HGImageRoi)); + } + + if (0 == type) + { + type = GetType(pImage); + } + + HGResult ret = HGBase_CreateImage(roi2.right - roi2.left, roi2.bottom - roi2.top, type, origin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_BGRA == type) + { + HBITMAP hBmp = NULL; + HGBase_GetHBITMAPOfImage(*image, &hBmp); + assert(NULL != hBmp); + + HDC hMem = CreateCompatibleDC(NULL); + HBITMAP hOldBmp = (HBITMAP)SelectObject(hMem, hBmp); + Gdiplus::Graphics graphics(hMem); + graphics.DrawImage(pImage, (INT)roi2.left, (INT)roi2.top, + (INT)(roi2.right - roi2.left), (INT)(roi2.bottom - roi2.top)); + SelectObject(hMem, hOldBmp); + DeleteDC(hMem); + ret = HGBASE_ERR_OK; + } + else + { + HGUInt type2 = HGBASE_IMGTYPE_BGR; + if (HGBASE_IMGTYPE_RGBA == type) + type2 = HGBASE_IMGTYPE_BGRA; + + HGImage image2 = NULL; + ret = LoadGdiImage(pImage, roi, type2, origin, &image2); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(image2, *image); + HGBase_DestroyImage(image2); + } + + if (HGBASE_ERR_OK != ret) + HGBase_DestroyImage(*image); + } + + if (HGBASE_ERR_OK == ret) + { + HGUInt xDpi = (HGUInt)pImage->GetHorizontalResolution(); + HGUInt yDpi = (HGUInt)pImage->GetVerticalResolution(); + HGBase_SetImageDpi(*image, xDpi, yDpi); + } + + return ret; +} + +HGResult HGAPI HGBase_CreateImageFromDIB(HGLOBAL hMem, const HGImageRoi* roi, + HGUInt type, HGUInt origin, HGImage* image) +{ + if (NULL == hMem || NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGResult ret = HGBASE_ERR_FAIL; + + ULONG size = (ULONG)GlobalSize(hMem); + void* pMem = GlobalLock(hMem); + if (NULL != pMem) + { + IStream* pStream = NULL; + HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); + if (SUCCEEDED(hr)) + { + ULONG writeSize = 0; + + BITMAPINFOHEADER* infoHeader = (BITMAPINFOHEADER*)pMem; + DWORD bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + if (infoHeader->biBitCount <= 8) + bfOffBits += ((HGUInt)(1 << infoHeader->biBitCount) * sizeof(RGBQUAD)); + + BITMAPFILEHEADER fileHeader = { 0 }; + fileHeader.bfType = 0x4D42; + fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + size; + fileHeader.bfOffBits = bfOffBits; + pStream->Write(&fileHeader, sizeof(BITMAPFILEHEADER), &writeSize); + pStream->Write(pMem, size, &writeSize); + + ULONG_PTR nToken = 0; + Gdiplus::GdiplusStartupInput input; + Gdiplus::GdiplusStartupOutput output; + Gdiplus::GdiplusStartup(&nToken, &input, &output); + assert(0 != nToken); + + Gdiplus::Image img(pStream); + Gdiplus::Status status = img.GetLastStatus(); + if (Gdiplus::Ok == status) + { + ret = LoadGdiImage(&img, roi, type, origin, image); + } + + Gdiplus::GdiplusShutdown(nToken); + nToken = 0; + pStream->Release(); + } + + GlobalUnlock(hMem); + } + + return ret; +} + +#endif /* HG_CMP_MSC */ + +HGResult HGAPI HGBase_CloneImage(HGImage srcImage, HGUInt type, HGUInt origin, HGImage* image) +{ + if (NULL == srcImage || NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* srcImageImpl = (HGImageImpl*)srcImage; + + if (0 == type) + { + type = srcImageImpl->m_type; + } + + if (0 == origin) + { + origin = srcImageImpl->m_origin; + } + + HGResult ret = HGBase_CreateImage(srcImageImpl->m_right - srcImageImpl->m_left, + srcImageImpl->m_bottom - srcImageImpl->m_top, type, origin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGBase_CopyImage(srcImage, *image); + if (HGBASE_ERR_OK != ret) + { + HGBase_DestroyImage(*image); + return ret; + } + + HGBase_SetImageDpi(*image, srcImageImpl->m_xDpi, srcImageImpl->m_yDpi); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_DestroyImage(HGImage image) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + delete imageImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetImageData(HGImage image, HGByte** data) +{ + if (NULL == image || NULL == data) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + *data = imageImpl->m_data; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetImageInfo(HGImage image, HGImageInfo* info) +{ + if (NULL == image || NULL == info) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + info->width = imageImpl->m_width; + info->height = imageImpl->m_height; + info->type = imageImpl->m_type; + info->widthStep = imageImpl->m_widthStep; + info->origin = imageImpl->m_origin; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetImageROI(HGImage image, HGImageRoi* roi) +{ + if (NULL == image || NULL == roi) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + roi->left = imageImpl->m_left; + roi->top = imageImpl->m_top; + roi->right = imageImpl->m_right; + roi->bottom = imageImpl->m_bottom; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_SetImageROI(HGImage image, const HGImageRoi* roi) +{ + if (NULL == image || NULL == roi) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + + if (roi->right <= roi->left || roi->bottom <= roi->top + || roi->right > imageImpl->m_width || roi->bottom > imageImpl->m_height) + { + return HGBASE_ERR_INVALIDARG; + } + + imageImpl->m_left = roi->left; + imageImpl->m_top = roi->top; + imageImpl->m_right = roi->right; + imageImpl->m_bottom = roi->bottom; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_ResetImageROI(HGImage image) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + imageImpl->m_left = 0; + imageImpl->m_top = 0; + imageImpl->m_right = imageImpl->m_width; + imageImpl->m_bottom = imageImpl->m_height; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetImageDpi(HGImage image, HGUInt* xDpi, HGUInt* yDpi) +{ + if (NULL == image || NULL == xDpi || NULL == yDpi) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + *xDpi = imageImpl->m_xDpi; + *yDpi = imageImpl->m_yDpi; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_SetImageDpi(HGImage image, HGUInt xDpi, HGUInt yDpi) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + imageImpl->m_xDpi = xDpi; + imageImpl->m_yDpi = yDpi; + return HGBASE_ERR_OK; +} + +#if defined(HG_CMP_MSC) + +HGResult HGAPI HGBase_GetHBITMAPOfImage(HGImage image, HBITMAP* hBmp) +{ + if (NULL == image || NULL == hBmp) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + *hBmp = imageImpl->m_hBmp; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CreateHBITMAPFromImage(HGImage image, HBITMAP* hBmp) +{ + return HGBASE_ERR_NOTIMPL; +} + +HGResult HGAPI HGBase_CreateDIBFromImage(HGImage image, HGLOBAL* hMem) +{ + return HGBASE_ERR_NOTIMPL; +} + +#endif /* HG_CMP_MSC */ + +HGResult HGAPI HGBase_ImageMirror(HGImage image, HGImage destImage) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + HGUInt width = imageImpl->m_width; + HGUInt height = imageImpl->m_height; + HGUInt type = imageImpl->m_type; + HGUInt widthStep = imageImpl->m_widthStep; + HGUInt origin = imageImpl->m_origin; + + HGUInt left = imageImpl->m_left; + HGUInt top = imageImpl->m_top; + HGUInt right = imageImpl->m_right; + HGUInt bottom = imageImpl->m_bottom; + HGByte* data = imageImpl->m_data; + + HGUInt roiWidth = right - left; + HGUInt roiHeight = bottom - top; + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ImageMirror(imageTmp, imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* p = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt step = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + p = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + step = -(HGInt)widthStep; + } + + if (3 == channels) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = p + (HGSize)i * (HGSize)step; + HGByte* pEx2 = pEx + dataSize - channels; + while (pEx < pEx2) + { + HGByte temp0 = pEx[0]; + pEx[0] = pEx2[0]; + pEx2[0] = temp0; + + HGByte temp1 = pEx[1]; + pEx[1] = pEx2[1]; + pEx2[1] = temp1; + + HGByte temp2 = pEx[2]; + pEx[2] = pEx2[2]; + pEx2[2] = temp2; + + pEx += 3; + pEx2 -= 3; + } + } + } + else if (4 == channels) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = p + (HGSize)i * (HGSize)step; + HGByte* pEx2 = pEx + dataSize - channels; + while (pEx < pEx2) + { + HGUInt tmp = *(HGUInt*)pEx; + *(HGUInt*)pEx = *(HGUInt*)pEx2; + *(HGUInt*)pEx2 = tmp; + pEx += 4; + pEx2 -= 4; + } + } + } + else + { + assert(1 == channels); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = p + (HGSize)i * (HGSize)step; + HGByte* pEx2 = pEx + dataSize - channels; + while (pEx < pEx2) + { + HGByte tmp = *pEx; + *pEx = *pEx2; + *pEx2 = tmp; + ++pEx; + --pEx2; + } + } + } + } + else + { + HGImageImpl* destImageImpl = (HGImageImpl*)destImage; + HGUInt destWidth = destImageImpl->m_width; + HGUInt destHeight = destImageImpl->m_height; + HGUInt destType = destImageImpl->m_type; + HGUInt destWidthStep = destImageImpl->m_widthStep; + HGUInt destOrigin = destImageImpl->m_origin; + + HGUInt destLeft = destImageImpl->m_left; + HGUInt destTop = destImageImpl->m_top; + HGUInt destRight = destImageImpl->m_right; + HGUInt destBottom = destImageImpl->m_bottom; + uint8_t* destData = destImageImpl->m_data; + + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (roiWidth != (destRight - destLeft) || roiHeight != (destBottom - destTop)) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ImageMirror(imageTmp, imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* src = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt srcStep = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + src = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + srcStep = -(HGInt)widthStep; + } + + HGByte* dest = destData + (HGUSize)destTop * (HGUSize)destWidthStep + destLeft * channels; + HGInt destStep = (HGInt)destWidthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destOrigin) + { + dest = destData + (HGUSize)(destHeight - destTop - 1) * (HGUSize)destWidthStep + destLeft * channels; + destStep = -(HGInt)destWidthStep; + } + + if (3 == channels) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep + dataSize - channels; + while (pEx < pExEnd) + { + pDestEx[0] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[2]; + pEx += 3; + pDestEx -= 3; + } + } + } + else if (4 == channels) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep + dataSize - channels; + while (pEx < pExEnd) + { + *(HGUInt*)pDestEx = *(HGUInt*)pEx; + pEx += 4; + pDestEx -= 4; + } + } + } + else + { + assert(1 == channels); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep + dataSize - channels; + while (pEx < pExEnd) + { + *pDestEx = *pEx; + ++pEx; + --pDestEx; + } + } + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_ImageFlip(HGImage image, HGImage destImage) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + HGUInt width = imageImpl->m_width; + HGUInt height = imageImpl->m_height; + HGUInt type = imageImpl->m_type; + HGUInt widthStep = imageImpl->m_widthStep; + HGUInt origin = imageImpl->m_origin; + + HGUInt left = imageImpl->m_left; + HGUInt top = imageImpl->m_top; + HGUInt right = imageImpl->m_right; + HGUInt bottom = imageImpl->m_bottom; + HGByte* data = imageImpl->m_data; + + HGUInt roiWidth = right - left; + HGUInt roiHeight = bottom - top; + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ImageFlip(imageTmp, imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* p1 = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt step1 = (HGInt)widthStep; + HGByte* p2 = data + (HGUSize)(bottom - 1) * (HGUSize)widthStep + left * channels; + HGInt step2 = -(HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + p1 = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + step1 = -(HGInt)widthStep; + p2 = data + (HGUSize)(height - bottom) * (HGUSize)widthStep + left * channels; + step2 = (HGInt)widthStep; + } + + uint32_t loop = roiHeight / 2; + + if (4 == channels) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)loop; ++i) + { + uint8_t* p1Ex = p1 + (HGSize)i * (HGSize)step1; + uint8_t* p1ExEnd = p1Ex + dataSize; + uint8_t* p2Ex = p2 + (HGSize)i * (HGSize)step2; + while (p1Ex < p1ExEnd) + { + HGUInt tmp = *(HGUInt*)p1Ex; + *(HGUInt*)p1Ex = *(HGUInt*)p2Ex; + *(HGUInt*)p2Ex = tmp; + p1Ex += 4; + p2Ex += 4; + } + } + } + else + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)loop; ++i) + { + uint8_t* p1Ex = p1 + (HGSize)i * (HGSize)step1; + uint8_t* p1ExEnd = p1Ex + dataSize; + uint8_t* p2Ex = p2 + (HGSize)i * (HGSize)step2; + while (p1Ex < p1ExEnd) + { + uint8_t temp = *p1Ex; + *p1Ex = *p2Ex; + *p2Ex = temp; + ++p1Ex; + ++p2Ex; + } + } + } + } + else + { + HGImageImpl* destImageImpl = (HGImageImpl*)destImage; + HGUInt destWidth = destImageImpl->m_width; + HGUInt destHeight = destImageImpl->m_height; + HGUInt destType = destImageImpl->m_type; + HGUInt destWidthStep = destImageImpl->m_widthStep; + HGUInt destOrigin = destImageImpl->m_origin; + + HGUInt destLeft = destImageImpl->m_left; + HGUInt destTop = destImageImpl->m_top; + HGUInt destRight = destImageImpl->m_right; + HGUInt destBottom = destImageImpl->m_bottom; + uint8_t* destData = destImageImpl->m_data; + + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (roiWidth != (destRight - destLeft) || roiHeight != (destBottom - destTop)) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ImageFlip(imageTmp, imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* src = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt srcStep = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + src = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + srcStep = -(HGInt)widthStep; + } + + HGByte* dest = destData + (HGUSize)(destBottom - 1) * (HGUSize)destWidthStep + destLeft * channels; + HGInt destStep = -(HGInt)destWidthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destOrigin) + { + dest = destData + (HGUSize)(destHeight - destBottom) * (HGUSize)destWidthStep + destLeft * channels; + destStep = (HGInt)destWidthStep; + } + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + memcpy(pDestEx, pEx, dataSize); + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_ImageRotateLeft(HGImage image, HGImage destImage) +{ + if (NULL == image || NULL == destImage || image == destImage) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + HGUInt width = imageImpl->m_width; + HGUInt height = imageImpl->m_height; + HGUInt type = imageImpl->m_type; + HGUInt widthStep = imageImpl->m_widthStep; + HGUInt origin = imageImpl->m_origin; + + HGUInt left = imageImpl->m_left; + HGUInt top = imageImpl->m_top; + HGUInt right = imageImpl->m_right; + HGUInt bottom = imageImpl->m_bottom; + HGByte* data = imageImpl->m_data; + + HGUInt roiWidth = right - left; + HGUInt roiHeight = bottom - top; + + HGImageImpl* destImageImpl = (HGImageImpl*)destImage; + HGUInt destWidth = destImageImpl->m_width; + HGUInt destHeight = destImageImpl->m_height; + HGUInt destType = destImageImpl->m_type; + HGUInt destWidthStep = destImageImpl->m_widthStep; + HGUInt destOrigin = destImageImpl->m_origin; + + HGUInt destLeft = destImageImpl->m_left; + HGUInt destTop = destImageImpl->m_top; + HGUInt destRight = destImageImpl->m_right; + HGUInt destBottom = destImageImpl->m_bottom; + uint8_t* destData = destImageImpl->m_data; + + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (roiWidth != (destBottom - destTop) || roiHeight != (destRight - destLeft)) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp1 = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp1); + if (HGBASE_ERR_OK == ret) + { + HGImageInfo imgInfo; + HGBase_GetImageInfo(imageTmp1, &imgInfo); + + HGImage imageTmp2 = NULL; + ret = HGBase_CreateImage(imgInfo.height, imgInfo.width, imgInfo.type, imgInfo.origin, &imageTmp2); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ImageRotateLeft(imageTmp1, imageTmp2); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp2, destImage); + } + + HGBase_DestroyImage(imageTmp2); + } + + HGBase_DestroyImage(imageTmp1); + } + + return ret; + } + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + HGInt span = (HGInt)channels * 32; + HGInt destSpan = (HGInt)destWidthStep * 32; + + uint8_t* p = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt step = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + p = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + step = -(HGInt)widthStep; + } + uint8_t* pEnd = p + dataSize; + uint8_t* pDest = destData + (HGUSize)destTop * (HGUSize)destWidthStep + destLeft * channels; + HGInt destStep = (HGInt)destWidthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destOrigin) + { + pDest = destData + (HGUSize)(destHeight - destTop - 1) * (HGUSize)destWidthStep + destLeft * channels; + destStep = -(HGInt)destWidthStep; + destSpan = -(HGInt)destWidthStep * 32; + } + pDest += (HGSize)(roiWidth - 1) * (HGSize)destStep; + + if (3 == channels) + { + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest + i * 3; + + while (pEx < pExEnd) + { + pDestEx[0] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[2]; + + pEx += 3; + pDestEx -= destStep; + } + } + + p += span; + pDest -= destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest + i * 3; + + pDestEx[0] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[2]; + } + + p += 3; + pDest -= destStep; + } + } + else if (4 == channels) + { + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest + i * 4; + + while (pEx < pExEnd) + { + *(HGUInt*)pDestEx = *(HGUInt*)pEx; + pEx += 4; + pDestEx -= destStep; + } + } + + p += span; + pDest -= destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest + i * 4; + *(HGUInt*)pDestEx = *(HGUInt*)pEx; + } + + p += 4; + pDest -= destStep; + } + } + else + { + assert(1 == channels); + + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest + i; + + while (pEx < pExEnd) + { + *pDestEx = *pEx; + ++pEx; + pDestEx -= destStep; + } + } + + p += span; + pDest -= destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest + i; + *pDestEx = *pEx; + } + + ++p; + pDest -= destStep; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_ImageRotateRight(HGImage image, HGImage destImage) +{ + if (NULL == image || NULL == destImage || image == destImage) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + HGUInt width = imageImpl->m_width; + HGUInt height = imageImpl->m_height; + HGUInt type = imageImpl->m_type; + HGUInt widthStep = imageImpl->m_widthStep; + HGUInt origin = imageImpl->m_origin; + + HGUInt left = imageImpl->m_left; + HGUInt top = imageImpl->m_top; + HGUInt right = imageImpl->m_right; + HGUInt bottom = imageImpl->m_bottom; + HGByte* data = imageImpl->m_data; + + HGUInt roiWidth = right - left; + HGUInt roiHeight = bottom - top; + + HGImageImpl* destImageImpl = (HGImageImpl*)destImage; + HGUInt destWidth = destImageImpl->m_width; + HGUInt destHeight = destImageImpl->m_height; + HGUInt destType = destImageImpl->m_type; + HGUInt destWidthStep = destImageImpl->m_widthStep; + HGUInt destOrigin = destImageImpl->m_origin; + + HGUInt destLeft = destImageImpl->m_left; + HGUInt destTop = destImageImpl->m_top; + HGUInt destRight = destImageImpl->m_right; + HGUInt destBottom = destImageImpl->m_bottom; + uint8_t* destData = destImageImpl->m_data; + + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (roiWidth != (destBottom - destTop) || roiHeight != (destRight - destLeft)) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp1 = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp1); + if (HGBASE_ERR_OK == ret) + { + HGImageInfo imgInfo; + HGBase_GetImageInfo(imageTmp1, &imgInfo); + + HGImage imageTmp2 = NULL; + ret = HGBase_CreateImage(imgInfo.height, imgInfo.width, imgInfo.type, imgInfo.origin, &imageTmp2); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ImageRotateRight(imageTmp1, imageTmp2); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp2, destImage); + } + + HGBase_DestroyImage(imageTmp2); + } + + HGBase_DestroyImage(imageTmp1); + } + + return ret; + } + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + HGInt span = (HGInt)channels * 32; + HGInt destSpan = (HGInt)destWidthStep * 32; + + uint8_t* p = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt step = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + p = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + step = -(HGInt)widthStep; + } + uint8_t* pEnd = p + dataSize; + uint8_t* pDest = destData + (HGUSize)destTop * (HGUSize)destWidthStep + destLeft * channels; + HGInt destStep = (HGInt)destWidthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destOrigin) + { + pDest = destData + (HGUSize)(destHeight - destTop - 1) * (HGUSize)destWidthStep + destLeft * channels; + destStep = -(HGInt)destWidthStep; + destSpan = -(HGInt)destWidthStep * 32; + } + pDest += (roiHeight - 1) * channels; + + if (3 == channels) + { + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest - i * 3; + + while (pEx < pExEnd) + { + pDestEx[0] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[2]; + + pEx += 3; + pDestEx += destStep; + } + } + + p += span; + pDest += destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest - i * 3; + + pDestEx[0] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[2]; + } + + p += 3; + pDest += destStep; + } + } + else if (4 == channels) + { + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest - i * 4; + + while (pEx < pExEnd) + { + *(HGUInt*)pDestEx = *(HGUInt*)pEx; + pEx += 4; + pDestEx += destStep; + } + } + + p += span; + pDest += destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest - i * 4; + *(HGUInt*)pDestEx = *(HGUInt*)pEx; + } + + p += 4; + pDest += destStep; + } + } + else + { + assert(1 == channels); + + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest - i; + + while (pEx < pExEnd) + { + *pDestEx = *pEx; + ++pEx; + pDestEx += destStep; + } + } + + p += span; + pDest += destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest - i; + *pDestEx = *pEx; + } + + ++p; + pDest += destStep; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_ImageRotateLeftMirror(HGImage image, HGImage destImage) +{ + if (NULL == image || NULL == destImage || image == destImage) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + HGUInt width = imageImpl->m_width; + HGUInt height = imageImpl->m_height; + HGUInt type = imageImpl->m_type; + HGUInt widthStep = imageImpl->m_widthStep; + HGUInt origin = imageImpl->m_origin; + + HGUInt left = imageImpl->m_left; + HGUInt top = imageImpl->m_top; + HGUInt right = imageImpl->m_right; + HGUInt bottom = imageImpl->m_bottom; + HGByte* data = imageImpl->m_data; + + HGUInt roiWidth = right - left; + HGUInt roiHeight = bottom - top; + + HGImageImpl* destImageImpl = (HGImageImpl*)destImage; + HGUInt destWidth = destImageImpl->m_width; + HGUInt destHeight = destImageImpl->m_height; + HGUInt destType = destImageImpl->m_type; + HGUInt destWidthStep = destImageImpl->m_widthStep; + HGUInt destOrigin = destImageImpl->m_origin; + + HGUInt destLeft = destImageImpl->m_left; + HGUInt destTop = destImageImpl->m_top; + HGUInt destRight = destImageImpl->m_right; + HGUInt destBottom = destImageImpl->m_bottom; + uint8_t* destData = destImageImpl->m_data; + + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (roiWidth != (destBottom - destTop) || roiHeight != (destRight - destLeft)) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp1 = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp1); + if (HGBASE_ERR_OK == ret) + { + HGImageInfo imgInfo; + HGBase_GetImageInfo(imageTmp1, &imgInfo); + + HGImage imageTmp2 = NULL; + ret = HGBase_CreateImage(imgInfo.height, imgInfo.width, imgInfo.type, imgInfo.origin, &imageTmp2); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ImageRotateLeftMirror(imageTmp1, imageTmp2); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp2, destImage); + } + + HGBase_DestroyImage(imageTmp2); + } + + HGBase_DestroyImage(imageTmp1); + } + + return ret; + } + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + HGInt span = (HGInt)channels * 32; + HGInt destSpan = (HGInt)destWidthStep * 32; + + uint8_t* p = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt step = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + p = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + step = -(HGInt)widthStep; + } + uint8_t* pEnd = p + dataSize; + uint8_t* pDest = destData + (HGUSize)destTop * (HGUSize)destWidthStep + destLeft * channels; + HGInt destStep = (HGInt)destWidthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destOrigin) + { + pDest = destData + (HGUSize)(destHeight - destTop - 1) * (HGUSize)destWidthStep + destLeft * channels; + destStep = -(HGInt)destWidthStep; + destSpan = -(HGInt)destWidthStep * 32; + } + pDest += (HGSize)(roiWidth - 1) * (HGSize)destStep; + pDest += (roiHeight - 1) * channels; + + if (3 == channels) + { + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest - i * 3; + + while (pEx < pExEnd) + { + pDestEx[0] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[2]; + + pEx += 3; + pDestEx -= destStep; + } + } + + p += span; + pDest -= destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest - i * 3; + + pDestEx[0] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[2]; + } + + p += 3; + pDest -= destStep; + } + } + else if (4 == channels) + { + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest - i * 4; + + while (pEx < pExEnd) + { + *(HGUInt*)pDestEx = *(HGUInt*)pEx; + pEx += 4; + pDestEx -= destStep; + } + } + + p += span; + pDest -= destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest - i * 4; + *(HGUInt*)pDestEx = *(HGUInt*)pEx; + } + + p += 4; + pDest -= destStep; + } + } + else + { + assert(1 == channels); + + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest - i; + + while (pEx < pExEnd) + { + *pDestEx = *pEx; + ++pEx; + pDestEx -= destStep; + } + } + + p += span; + pDest -= destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest - i; + *pDestEx = *pEx; + } + + ++p; + pDest -= destStep; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_ImageRotateRightMirror(HGImage image, HGImage destImage) +{ + if (NULL == image || NULL == destImage || image == destImage) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + HGUInt width = imageImpl->m_width; + HGUInt height = imageImpl->m_height; + HGUInt type = imageImpl->m_type; + HGUInt widthStep = imageImpl->m_widthStep; + HGUInt origin = imageImpl->m_origin; + + HGUInt left = imageImpl->m_left; + HGUInt top = imageImpl->m_top; + HGUInt right = imageImpl->m_right; + HGUInt bottom = imageImpl->m_bottom; + HGByte* data = imageImpl->m_data; + + HGUInt roiWidth = right - left; + HGUInt roiHeight = bottom - top; + + HGImageImpl* destImageImpl = (HGImageImpl*)destImage; + HGUInt destWidth = destImageImpl->m_width; + HGUInt destHeight = destImageImpl->m_height; + HGUInt destType = destImageImpl->m_type; + HGUInt destWidthStep = destImageImpl->m_widthStep; + HGUInt destOrigin = destImageImpl->m_origin; + + HGUInt destLeft = destImageImpl->m_left; + HGUInt destTop = destImageImpl->m_top; + HGUInt destRight = destImageImpl->m_right; + HGUInt destBottom = destImageImpl->m_bottom; + uint8_t* destData = destImageImpl->m_data; + + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (roiWidth != (destBottom - destTop) || roiHeight != (destRight - destLeft)) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp1 = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp1); + if (HGBASE_ERR_OK == ret) + { + HGImageInfo imgInfo; + HGBase_GetImageInfo(imageTmp1, &imgInfo); + + HGImage imageTmp2 = NULL; + ret = HGBase_CreateImage(imgInfo.height, imgInfo.width, imgInfo.type, imgInfo.origin, &imageTmp2); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ImageRotateRightMirror(imageTmp1, imageTmp2); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp2, destImage); + } + + HGBase_DestroyImage(imageTmp2); + } + + HGBase_DestroyImage(imageTmp1); + } + + return ret; + } + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + HGInt span = (HGInt)channels * 32; + HGInt destSpan = (HGInt)destWidthStep * 32; + + uint8_t* p = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt step = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + p = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + step = -(HGInt)widthStep; + } + uint8_t* pEnd = p + dataSize; + uint8_t* pDest = destData + (HGUSize)destTop * (HGUSize)destWidthStep + destLeft * channels; + HGInt destStep = (HGInt)destWidthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destOrigin) + { + pDest = destData + (HGUSize)(destHeight - destTop - 1) * (HGUSize)destWidthStep + destLeft * channels; + destStep = -(HGInt)destWidthStep; + destSpan = -(HGInt)destWidthStep * 32; + } + + if (3 == channels) + { + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest + i * 3; + + while (pEx < pExEnd) + { + pDestEx[0] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[2]; + + pEx += 3; + pDestEx += destStep; + } + } + + p += span; + pDest += destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest + i * 3; + + pDestEx[0] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[2]; + } + + p += 3; + pDest += destStep; + } + } + else if (4 == channels) + { + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest + i * 4; + + while (pEx < pExEnd) + { + *(HGUInt*)pDestEx = *(HGUInt*)pEx; + pEx += 4; + pDestEx += destStep; + } + } + + p += span; + pDest += destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest + i * 4; + *(HGUInt*)pDestEx = *(HGUInt*)pEx; + } + + p += 4; + pDest += destStep; + } + } + else + { + assert(1 == channels); + + while (p + span <= pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + span; + uint8_t* pDestEx = pDest + i; + + while (pEx < pExEnd) + { + *pDestEx = *pEx; + ++pEx; + pDestEx += destStep; + } + } + + p += span; + pDest += destSpan; + } + + while (p < pEnd) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pDestEx = pDest + i; + *pDestEx = *pEx; + } + + ++p; + pDest += destStep; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_ImageRotate180(HGImage image, HGImage destImage) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + HGUInt width = imageImpl->m_width; + HGUInt height = imageImpl->m_height; + HGUInt type = imageImpl->m_type; + HGUInt widthStep = imageImpl->m_widthStep; + HGUInt origin = imageImpl->m_origin; + + HGUInt left = imageImpl->m_left; + HGUInt top = imageImpl->m_top; + HGUInt right = imageImpl->m_right; + HGUInt bottom = imageImpl->m_bottom; + HGByte* data = imageImpl->m_data; + + HGUInt roiWidth = right - left; + HGUInt roiHeight = bottom - top; + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ImageRotate180(imageTmp, imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* p1 = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt step1 = (HGInt)widthStep; + HGByte* p2 = data + (HGUSize)(bottom - 1) * (HGUSize)widthStep + left * channels; + HGInt step2 = -(HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + p1 = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + step1 = -(HGInt)widthStep; + p2 = data + (HGUSize)(height - bottom) * (HGUSize)widthStep + left * channels; + step2 = (HGInt)widthStep; + } + + if (3 == channels) + { + HGUInt loop = roiHeight / 2; + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)loop; ++i) + { + HGByte* p1Ex = p1 + (HGSize)i * (HGSize)step1; + HGByte* p1ExEnd = p1Ex + dataSize; + HGByte* p2Ex = p2 + (HGSize)i * (HGSize)step2 + dataSize - channels; + while (p1Ex < p1ExEnd) + { + HGByte temp0 = p1Ex[0]; + p1Ex[0] = p2Ex[0]; + p2Ex[0] = temp0; + + HGByte temp1 = p1Ex[1]; + p1Ex[1] = p2Ex[1]; + p2Ex[1] = temp1; + + HGByte temp2 = p1Ex[2]; + p1Ex[2] = p2Ex[2]; + p2Ex[2] = temp2; + + p1Ex += 3; + p2Ex -= 3; + } + } + + if (0 != roiHeight % 2) + { + HGByte* p1Ex = p1 + (HGSize)loop * (HGSize)step1; + HGByte* p2Ex = p2 + (HGSize)loop * (HGSize)step2 + dataSize - channels; + while (p1Ex < p2Ex) + { + HGByte temp0 = p1Ex[0]; + p1Ex[0] = p2Ex[0]; + p2Ex[0] = temp0; + + HGByte temp1 = p1Ex[1]; + p1Ex[1] = p2Ex[1]; + p2Ex[1] = temp1; + + HGByte temp2 = p1Ex[2]; + p1Ex[2] = p2Ex[2]; + p2Ex[2] = temp2; + + p1Ex += 3; + p2Ex -= 3; + } + } + } + else if (4 == channels) + { + HGUInt loop = roiHeight / 2; + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)loop; ++i) + { + HGByte* p1Ex = p1 + (HGSize)i * (HGSize)step1; + HGByte* p1ExEnd = p1Ex + dataSize; + HGByte* p2Ex = p2 + (HGSize)i * (HGSize)step2 + dataSize - channels; + while (p1Ex < p1ExEnd) + { + HGUInt tmp = *(HGUInt*)p1Ex; + *(HGUInt*)p1Ex = *(HGUInt*)p2Ex; + *(HGUInt*)p2Ex = tmp; + p1Ex += 4; + p2Ex -= 4; + } + } + + if (0 != roiHeight % 2) + { + HGByte* p1Ex = p1 + (HGSize)loop * (HGSize)step1; + HGByte* p2Ex = p2 + (HGSize)loop * (HGSize)step2 + dataSize - channels; + while (p1Ex < p2Ex) + { + HGUInt tmp = *(HGUInt*)p1Ex; + *(HGUInt*)p1Ex = *(HGUInt*)p2Ex; + *(HGUInt*)p2Ex = tmp; + p1Ex += 4; + p2Ex -= 4; + } + } + } + else + { + assert(1 == channels); + + HGUInt loop = roiHeight / 2; + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)loop; ++i) + { + HGByte* p1Ex = p1 + (HGSize)i * (HGSize)step1; + HGByte* p1ExEnd = p1Ex + dataSize; + HGByte* p2Ex = p2 + (HGSize)i * (HGSize)step2 + dataSize - channels; + while (p1Ex < p1ExEnd) + { + HGByte tmp = *p1Ex; + *p1Ex = *p2Ex; + *p2Ex = tmp; + ++p1Ex; + --p2Ex; + } + } + + if (0 != roiHeight % 2) + { + HGByte* p1Ex = p1 + (HGSize)loop * (HGSize)step1; + HGByte* p2Ex = p2 + (HGSize)loop * (HGSize)step2 + dataSize - channels; + while (p1Ex < p2Ex) + { + HGByte tmp = *p1Ex; + *p1Ex = *p2Ex; + *p2Ex = tmp; + ++p1Ex; + --p2Ex; + } + } + } + } + else + { + HGImageImpl* destImageImpl = (HGImageImpl*)destImage; + HGUInt destWidth = destImageImpl->m_width; + HGUInt destHeight = destImageImpl->m_height; + HGUInt destType = destImageImpl->m_type; + HGUInt destWidthStep = destImageImpl->m_widthStep; + HGUInt destOrigin = destImageImpl->m_origin; + + HGUInt destLeft = destImageImpl->m_left; + HGUInt destTop = destImageImpl->m_top; + HGUInt destRight = destImageImpl->m_right; + HGUInt destBottom = destImageImpl->m_bottom; + uint8_t* destData = destImageImpl->m_data; + + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (roiWidth != (destRight - destLeft) || roiHeight != (destBottom - destTop)) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ImageRotate180(imageTmp, imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* src = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt srcStep = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + src = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + srcStep = -(HGInt)widthStep; + } + + HGByte* dest = destData + (HGUSize)(destBottom - 1) * (HGUSize)destWidthStep + destLeft * channels; + HGInt destStep = -(HGInt)destWidthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destOrigin) + { + dest = destData + (HGUSize)(destHeight - destBottom) * (HGUSize)destWidthStep + destLeft * channels; + destStep = (HGInt)destWidthStep; + } + + if (3 == channels) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* p1Ex = src + (HGSize)i * (HGSize)srcStep; + HGByte* p1ExEnd = p1Ex + dataSize; + HGByte* p2Ex = dest + (HGSize)i * (HGSize)destStep + dataSize - channels; + while (p1Ex < p1ExEnd) + { + p2Ex[0] = p1Ex[0]; + p2Ex[1] = p1Ex[1]; + p2Ex[2] = p1Ex[2]; + p1Ex += 3; + p2Ex -= 3; + } + } + } + else if (4 == channels) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* p1Ex = src + (HGSize)i * (HGSize)srcStep; + HGByte* p1ExEnd = p1Ex + dataSize; + HGByte* p2Ex = dest + (HGSize)i * (HGSize)destStep + dataSize - channels; + while (p1Ex < p1ExEnd) + { + *(HGUInt*)p2Ex = *(HGUInt*)p1Ex; + p1Ex += 4; + p2Ex -= 4; + } + } + } + else + { + assert(1 == channels); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* p1Ex = src + (HGSize)i * (HGSize)srcStep; + HGByte* p1ExEnd = p1Ex + dataSize; + HGByte* p2Ex = dest + (HGSize)i * (HGSize)destStep + dataSize - channels; + while (p1Ex < p1ExEnd) + { + *p2Ex = *p1Ex; + ++p1Ex; + --p2Ex; + } + } + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_ImageGrayscale(HGImage image, HGImage destImage) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + HGUInt width = imageImpl->m_width; + HGUInt height = imageImpl->m_height; + HGUInt type = imageImpl->m_type; + HGUInt widthStep = imageImpl->m_widthStep; + HGUInt origin = imageImpl->m_origin; + + HGUInt left = imageImpl->m_left; + HGUInt top = imageImpl->m_top; + HGUInt right = imageImpl->m_right; + HGUInt bottom = imageImpl->m_bottom; + HGByte* data = imageImpl->m_data; + + HGUInt roiWidth = right - left; + HGUInt roiHeight = bottom - top; + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BINARY == type) + { + return HGBASE_ERR_OK; + } + + HGByte* p = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt step = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + p = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + step = -(HGInt)widthStep; + } + + if (HGBASE_IMGTYPE_RGB == type || HGBASE_IMGTYPE_RGBA == type) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + dataSize; + + while (pEx < pExEnd) + { + uint8_t value = (pEx[0] * 76 + pEx[1] * 150 + pEx[2] * 30) >> 8; + pEx[0] = pEx[1] = pEx[2] = value; + pEx += channels; + } + } + } + else if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_BGRA == type) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + dataSize; + + while (pEx < pExEnd) + { + uint8_t value = (pEx[2] * 76 + pEx[1] * 150 + pEx[0] * 30) >> 8; + pEx[0] = pEx[1] = pEx[2] = value; + pEx += channels; + } + } + } + else + { + assert(HGBASE_IMGTYPE_GRAY == type); + } + } + else + { + HGImageImpl* destImageImpl = (HGImageImpl*)destImage; + HGUInt destWidth = destImageImpl->m_width; + HGUInt destHeight = destImageImpl->m_height; + HGUInt destType = destImageImpl->m_type; + HGUInt destWidthStep = destImageImpl->m_widthStep; + HGUInt destOrigin = destImageImpl->m_origin; + + HGUInt destLeft = destImageImpl->m_left; + HGUInt destTop = destImageImpl->m_top; + HGUInt destRight = destImageImpl->m_right; + HGUInt destBottom = destImageImpl->m_bottom; + uint8_t* destData = destImageImpl->m_data; + + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (roiWidth != (destRight - destLeft) || roiHeight != (destBottom - destTop)) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + return HGBase_CopyImage(image, destImage); + } + + HGByte* src = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt srcStep = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + src = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + srcStep = -(HGInt)widthStep; + } + + HGByte* dest = destData + (HGUSize)destTop * (HGUSize)destWidthStep + destLeft * channels; + HGInt destStep = (HGInt)destWidthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destOrigin) + { + dest = destData + (HGUSize)(destHeight - destTop - 1) * (HGUSize)destWidthStep + destLeft * channels; + destStep = -(HGInt)destWidthStep; + } + + if (HGBASE_IMGTYPE_RGB == type || HGBASE_IMGTYPE_RGBA == type) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + while (pEx < pExEnd) + { + uint8_t value = (pEx[0] * 76 + pEx[1] * 150 + pEx[2] * 30) >> 8; + pDestEx[0] = pDestEx[1] = pDestEx[2] = value; + + pEx += channels; + pDestEx += channels; + } + } + } + else if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_BGRA == type) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + while (pEx < pExEnd) + { + uint8_t value = (pEx[2] * 76 + pEx[1] * 150 + pEx[0] * 30) >> 8; + pDestEx[0] = pDestEx[1] = pDestEx[2] = value; + + pEx += channels; + pDestEx += channels; + } + } + } + else + { + assert(HGBASE_IMGTYPE_GRAY == type); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + memcpy(pDestEx, pEx, dataSize); + } + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_ReverseImage(HGImage image, HGImage destImage) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + HGUInt width = imageImpl->m_width; + HGUInt height = imageImpl->m_height; + HGUInt type = imageImpl->m_type; + HGUInt widthStep = imageImpl->m_widthStep; + HGUInt origin = imageImpl->m_origin; + + HGUInt left = imageImpl->m_left; + HGUInt top = imageImpl->m_top; + HGUInt right = imageImpl->m_right; + HGUInt bottom = imageImpl->m_bottom; + HGByte* data = imageImpl->m_data; + + HGUInt roiWidth = right - left; + HGUInt roiHeight = bottom - top; + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ReverseImage(imageTmp, imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* p = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt step = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + p = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + step = -(HGInt)widthStep; + } + + if (4 == channels) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + dataSize; + + while (pEx < pExEnd) + { + HGUInt temp = *(HGUInt*)pEx; + temp = ~temp; + *(HGUInt*)pEx = temp; + pEx += 4; + } + } + } + else + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + uint8_t* pExEnd = pEx + dataSize; + + while (pEx < pExEnd) + { + uint8_t temp = *pEx; + temp = ~temp; + *pEx = temp; + ++pEx; + } + } + } + } + else + { + HGImageImpl* destImageImpl = (HGImageImpl*)destImage; + HGUInt destWidth = destImageImpl->m_width; + HGUInt destHeight = destImageImpl->m_height; + HGUInt destType = destImageImpl->m_type; + HGUInt destWidthStep = destImageImpl->m_widthStep; + HGUInt destOrigin = destImageImpl->m_origin; + + HGUInt destLeft = destImageImpl->m_left; + HGUInt destTop = destImageImpl->m_top; + HGUInt destRight = destImageImpl->m_right; + HGUInt destBottom = destImageImpl->m_bottom; + uint8_t* destData = destImageImpl->m_data; + + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (roiWidth != (destRight - destLeft) || roiHeight != (destBottom - destTop)) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_ReverseImage(imageTmp, imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* src = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt srcStep = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + src = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + srcStep = -(HGInt)widthStep; + } + + HGByte* dest = destData + (HGUSize)destTop * (HGUSize)destWidthStep + destLeft * channels; + HGInt destStep = (HGInt)destWidthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destOrigin) + { + dest = destData + (HGUSize)(destHeight - destTop - 1) * (HGUSize)destWidthStep + destLeft * channels; + destStep = -(HGInt)destWidthStep; + } + + if (4 == channels) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + while (pEx < pExEnd) + { + HGUInt temp = *(HGUInt*)pEx; + temp = ~temp; + *(HGUInt*)pDestEx = temp; + + pEx += 4; + pDestEx += 4; + } + } + } + else + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + while (pEx < pExEnd) + { + uint8_t temp = *pEx; + temp = ~temp; + *pDestEx = temp; + + ++pEx; + ++pDestEx; + } + } + } + } + + return HGBASE_ERR_OK; +} + +static inline HGByte GetBit(const HGByte* data, HGUInt index) +{ + HGUInt byteIndex = index / 8; + HGUInt bitIndex = index % 8; + return (data[byteIndex] >> (7 - bitIndex)) & 0x01; +} + +static inline void SetBit(HGByte* data, HGUInt index, HGByte value) +{ + assert(0 == value || 1 == value); + HGUInt byteIndex = index / 8; + HGUInt bitIndex = index % 8; + if (1 == value) + data[byteIndex] |= (1 << (7 - bitIndex)); + else + data[byteIndex] &= ~(1 << (7 - bitIndex)); +} + +static HGResult CopyImageWithBinary(HGImageImpl *srcImageImpl, HGImageImpl *destImageImpl) +{ + assert(HGBASE_IMGTYPE_BINARY == srcImageImpl->m_type + || HGBASE_IMGTYPE_BINARY == destImageImpl->m_type); + + HGByte* src = srcImageImpl->m_data + (HGUSize)srcImageImpl->m_top * (HGUSize)srcImageImpl->m_widthStep; + HGInt srcStep = (HGInt)srcImageImpl->m_widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == srcImageImpl->m_origin) + { + src = srcImageImpl->m_data + (HGUSize)(srcImageImpl->m_height - srcImageImpl->m_top - 1) * (HGUSize)srcImageImpl->m_widthStep; + srcStep = -(HGInt)srcImageImpl->m_widthStep; + } + + HGByte* dest = destImageImpl->m_data + (HGUSize)destImageImpl->m_top * (HGUSize)destImageImpl->m_widthStep; + HGInt destStep = (HGInt)destImageImpl->m_widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destImageImpl->m_origin) + { + dest = destImageImpl->m_data + (HGUSize)(destImageImpl->m_height - destImageImpl->m_top - 1) * (HGUSize)destImageImpl->m_widthStep; + destStep = -(HGInt)destImageImpl->m_widthStep; + } + + if (HGBASE_IMGTYPE_BINARY == srcImageImpl->m_type) + { + if (HGBASE_IMGTYPE_BINARY == destImageImpl->m_type) + { + for (int32_t i = 0; i < (int32_t)(srcImageImpl->m_bottom - srcImageImpl->m_top); ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + for (int32_t j = 0; j < (int32_t)(srcImageImpl->m_right - srcImageImpl->m_left); ++j) + { + HGByte value = GetBit(pSrcEx, srcImageImpl->m_left + j); + SetBit(pDestEx, destImageImpl->m_left + j, value); + } + } + } + else if (HGBASE_IMGTYPE_GRAY == destImageImpl->m_type) + { + for (int32_t i = 0; i < (int32_t)(srcImageImpl->m_bottom - srcImageImpl->m_top); ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + for (int32_t j = 0; j < (int32_t)(srcImageImpl->m_right - srcImageImpl->m_left); ++j) + { + HGByte value = GetBit(pSrcEx, srcImageImpl->m_left + j); + pDestEx[destImageImpl->m_left + j] = (0 == value) ? 0 : 255; + } + } + } + else if (HGBASE_IMGTYPE_BGR == destImageImpl->m_type || HGBASE_IMGTYPE_RGB == destImageImpl->m_type) + { + for (int32_t i = 0; i < (int32_t)(srcImageImpl->m_bottom - srcImageImpl->m_top); ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + for (int32_t j = 0; j < (int32_t)(srcImageImpl->m_right - srcImageImpl->m_left); ++j) + { + HGByte value = GetBit(pSrcEx, srcImageImpl->m_left + j); + pDestEx[(destImageImpl->m_left + j) * 3] = (0 == value) ? 0 : 255; + pDestEx[(destImageImpl->m_left + j) * 3 + 1] = (0 == value) ? 0 : 255; + pDestEx[(destImageImpl->m_left + j) * 3 + 2] = (0 == value) ? 0 : 255; + } + } + } + else + { + assert(HGBASE_IMGTYPE_BGRA == destImageImpl->m_type || HGBASE_IMGTYPE_RGBA == destImageImpl->m_type); + + for (int32_t i = 0; i < (int32_t)(srcImageImpl->m_bottom - srcImageImpl->m_top); ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + for (int32_t j = 0; j < (int32_t)(srcImageImpl->m_right - srcImageImpl->m_left); ++j) + { + HGByte value = GetBit(pSrcEx, srcImageImpl->m_left + j); + pDestEx[(destImageImpl->m_left + j) * 4] = (0 == value) ? 0 : 255; + pDestEx[(destImageImpl->m_left + j) * 4 + 1] = (0 == value) ? 0 : 255; + pDestEx[(destImageImpl->m_left + j) * 4 + 2] = (0 == value) ? 0 : 255; + } + } + } + } + else + { + assert(HGBASE_IMGTYPE_BINARY == destImageImpl->m_type); + + if (HGBASE_IMGTYPE_GRAY == srcImageImpl->m_type) + { + for (int32_t i = 0; i < (int32_t)(srcImageImpl->m_bottom - srcImageImpl->m_top); ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + for (int32_t j = 0; j < (int32_t)(srcImageImpl->m_right - srcImageImpl->m_left); ++j) + { + HGByte v = pSrcEx[srcImageImpl->m_left + j]; + SetBit(pDestEx, destImageImpl->m_left + j, (v >= 128 ? 1 : 0)); + } + } + } + else if (HGBASE_IMGTYPE_BGR == srcImageImpl->m_type) + { + for (int32_t i = 0; i < (int32_t)(srcImageImpl->m_bottom - srcImageImpl->m_top); ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + for (int32_t j = 0; j < (int32_t)(srcImageImpl->m_right - srcImageImpl->m_left); ++j) + { + HGInt b = pSrcEx[(srcImageImpl->m_left + j) * 3]; + HGInt g = pSrcEx[(srcImageImpl->m_left + j) * 3 + 1]; + HGInt r = pSrcEx[(srcImageImpl->m_left + j) * 3 + 2]; + HGByte v = (r * 76 + g * 150 + b * 30) >> 8; + SetBit(pDestEx, destImageImpl->m_left + j, (v >= 128 ? 1 : 0)); + } + } + } + else if (HGBASE_IMGTYPE_RGB == srcImageImpl->m_type) + { + for (int32_t i = 0; i < (int32_t)(srcImageImpl->m_bottom - srcImageImpl->m_top); ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + for (int32_t j = 0; j < (int32_t)(srcImageImpl->m_right - srcImageImpl->m_left); ++j) + { + HGInt r = pSrcEx[(srcImageImpl->m_left + j) * 3]; + HGInt g = pSrcEx[(srcImageImpl->m_left + j) * 3 + 1]; + HGInt b = pSrcEx[(srcImageImpl->m_left + j) * 3 + 2]; + HGByte v = (r * 76 + g * 150 + b * 30) >> 8; + SetBit(pDestEx, destImageImpl->m_left + j, (v >= 128 ? 1 : 0)); + } + } + } + else if (HGBASE_IMGTYPE_BGRA == srcImageImpl->m_type) + { + for (int32_t i = 0; i < (int32_t)(srcImageImpl->m_bottom - srcImageImpl->m_top); ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + for (int32_t j = 0; j < (int32_t)(srcImageImpl->m_right - srcImageImpl->m_left); ++j) + { + HGInt b = pSrcEx[(srcImageImpl->m_left + j) * 4]; + HGInt g = pSrcEx[(srcImageImpl->m_left + j) * 4 + 1]; + HGInt r = pSrcEx[(srcImageImpl->m_left + j) * 4 + 2]; + HGByte v = (r * 76 + g * 150 + b * 30) >> 8; + SetBit(pDestEx, destImageImpl->m_left + j, (v >= 128 ? 1 : 0)); + } + } + } + else if (HGBASE_IMGTYPE_RGBA == srcImageImpl->m_type) + { + for (int32_t i = 0; i < (int32_t)(srcImageImpl->m_bottom - srcImageImpl->m_top); ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + for (int32_t j = 0; j < (int32_t)(srcImageImpl->m_right - srcImageImpl->m_left); ++j) + { + HGInt r = pSrcEx[(srcImageImpl->m_left + j) * 4]; + HGInt g = pSrcEx[(srcImageImpl->m_left + j) * 4 + 1]; + HGInt b = pSrcEx[(srcImageImpl->m_left + j) * 4 + 2]; + HGByte v = (r * 76 + g * 150 + b * 30) >> 8; + SetBit(pDestEx, destImageImpl->m_left + j, (v >= 128 ? 1 : 0)); + } + } + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CopyImage(HGImage image, HGImage destImage) +{ + if (NULL == image || NULL == destImage || image == destImage) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageImpl* imageImpl = (HGImageImpl*)image; + HGUInt width = imageImpl->m_width; + HGUInt height = imageImpl->m_height; + HGUInt type = imageImpl->m_type; + HGUInt widthStep = imageImpl->m_widthStep; + HGUInt origin = imageImpl->m_origin; + + HGUInt left = imageImpl->m_left; + HGUInt top = imageImpl->m_top; + HGUInt right = imageImpl->m_right; + HGUInt bottom = imageImpl->m_bottom; + HGByte* data = imageImpl->m_data; + + HGUInt roiWidth = right - left; + HGUInt roiHeight = bottom - top; + + HGImageImpl* destImageImpl = (HGImageImpl*)destImage; + HGUInt destWidth = destImageImpl->m_width; + HGUInt destHeight = destImageImpl->m_height; + HGUInt destType = destImageImpl->m_type; + HGUInt destWidthStep = destImageImpl->m_widthStep; + HGUInt destOrigin = destImageImpl->m_origin; + + HGUInt destLeft = destImageImpl->m_left; + HGUInt destTop = destImageImpl->m_top; + HGUInt destRight = destImageImpl->m_right; + HGUInt destBottom = destImageImpl->m_bottom; + uint8_t* destData = destImageImpl->m_data; + + if (roiWidth != (destRight - destLeft) || roiHeight != (destBottom - destTop)) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type || HGBASE_IMGTYPE_BINARY == destType) + { + return CopyImageWithBinary(imageImpl, destImageImpl); + } + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + uint32_t destChannels = 1; + if (HGBASE_IMGTYPE_BGR == destType || HGBASE_IMGTYPE_RGB == destType) + destChannels = 3; + else if (HGBASE_IMGTYPE_BGRA == destType || HGBASE_IMGTYPE_RGBA == destType) + destChannels = 4; + + HGByte* src = data + (HGUSize)top * (HGUSize)widthStep + left * channels; + HGInt srcStep = (HGInt)widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + src = data + (HGUSize)(height - top - 1) * (HGUSize)widthStep + left * channels; + srcStep = -(HGInt)widthStep; + } + + HGByte* dest = destData + (HGUSize)destTop * (HGUSize)destWidthStep + destLeft * destChannels; + HGInt destStep = (HGInt)destWidthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destOrigin) + { + dest = destData + (HGUSize)(destHeight - destTop - 1) * (HGUSize)destWidthStep + destLeft * destChannels; + destStep = -(HGInt)destWidthStep; + } + + if (type == destType) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + memcpy(pDestEx, pEx, dataSize); + } + } + else + { + if (HGBASE_IMGTYPE_GRAY == type) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + while (pEx < pExEnd) + { + pDestEx[0] = pDestEx[1] = pDestEx[2] = *pEx; + ++pEx; + pDestEx += destChannels; + } + } + } + else if (HGBASE_IMGTYPE_GRAY == destType) + { + if (HGBASE_IMGTYPE_RGB == type || HGBASE_IMGTYPE_RGBA == type) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + while (pEx < pExEnd) + { + uint8_t value = (pEx[0] * 76 + pEx[1] * 150 + pEx[2] * 30) >> 8; + *pDestEx = value; + + pEx += channels; + ++pDestEx; + } + } + } + else + { + assert(HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_BGRA == type); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + while (pEx < pExEnd) + { + uint8_t value = (pEx[2] * 76 + pEx[1] * 150 + pEx[0] * 30) >> 8; + *pDestEx = value; + + pEx += channels; + ++pDestEx; + } + } + } + } + else if ((HGBASE_IMGTYPE_RGB == type && HGBASE_IMGTYPE_RGBA == destType) + || (HGBASE_IMGTYPE_BGR == type && HGBASE_IMGTYPE_BGRA == destType) + || (HGBASE_IMGTYPE_RGBA == type && HGBASE_IMGTYPE_RGB == destType) + || (HGBASE_IMGTYPE_BGRA == type && HGBASE_IMGTYPE_BGR == destType)) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + while (pEx < pExEnd) + { + pDestEx[0] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[2]; + + pEx += channels; + pDestEx += destChannels; + } + } + } + else + { + assert((HGBASE_IMGTYPE_RGB == type && HGBASE_IMGTYPE_BGRA == destType) + || (HGBASE_IMGTYPE_BGR == type && HGBASE_IMGTYPE_RGBA == destType) + || (HGBASE_IMGTYPE_RGBA == type && HGBASE_IMGTYPE_BGRA == destType) + || (HGBASE_IMGTYPE_BGRA == type && HGBASE_IMGTYPE_RGBA == destType) + || (HGBASE_IMGTYPE_RGBA == type && HGBASE_IMGTYPE_BGR == destType) + || (HGBASE_IMGTYPE_BGRA == type && HGBASE_IMGTYPE_RGB == destType) + || (HGBASE_IMGTYPE_BGR == type && HGBASE_IMGTYPE_RGB == destType) + || (HGBASE_IMGTYPE_RGB == type && HGBASE_IMGTYPE_BGR == destType)); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pExEnd = pEx + dataSize; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + + while (pEx < pExEnd) + { + pDestEx[2] = pEx[0]; + pDestEx[1] = pEx[1]; + pDestEx[0] = pEx[2]; + + pEx += channels; + pDestEx += destChannels; + } + } + } + } + + return HGBASE_ERR_OK; +} diff --git a/app/modules/base/HGImage.h b/app/modules/base/HGImage.h new file mode 100644 index 0000000..cd87fdf --- /dev/null +++ b/app/modules/base/HGImage.h @@ -0,0 +1,391 @@ +#ifndef __HGIMAGE_H__ +#define __HGIMAGE_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" +#if defined(HG_CMP_MSC) +#include +#endif + +HG_DECLARE_HANDLE(HGImage); + +/* 1位黑白图 */ +#define HGBASE_IMGTYPE_BINARY 1L +/* 8位灰度图 */ +#define HGBASE_IMGTYPE_GRAY 2L +/* 24位真彩色,B8G8R8格式 */ +#define HGBASE_IMGTYPE_BGR 3L +/* 24位真彩色,R8G8B8格式 */ +#define HGBASE_IMGTYPE_RGB 4L +/* 32位真彩色,带Alpha通道,B8G8R8A8格式 */ +#define HGBASE_IMGTYPE_BGRA 5L +/* 32位真彩色,带Alpha通道,R8G8B8A8格式 */ +#define HGBASE_IMGTYPE_RGBA 6L + +/* 顶左结构 */ +#define HGBASE_IMGORIGIN_TOP 1L +/* 底左结构 */ +#define HGBASE_IMGORIGIN_BOTTOM 2L + +#pragma pack(push) +#pragma pack(4) + +/* 图像信息 */ +typedef struct +{ + HGUInt width; /* 宽(像素),列数 */ + HGUInt height; /* 高(像素),行数 */ + HGUInt type; /* 类型,参见HGBASE_IMGTYPE_* */ + HGUInt widthStep; /* 每行的字节数 */ + HGUInt origin; /* 数据排列方式,参见HGBASE_IMGORIGIN_* */ +}HGImageInfo; + +/* 图像感兴趣区域 */ +typedef struct +{ + HGUInt left; + HGUInt top; + HGUInt right; + HGUInt bottom; +}HGImageRoi; + +#pragma pack(pop) + +/* 创建空白的新图像 +* 参数: +* 1) width: in, 新图像宽度 +* 2) height: in, 新图像高度 +* 3) type: in, 新图像类型 +* 4) origin: in, 新图像的数据排列方式 +* 5) image: out,新图像句柄 +* 说明: +* 1)在windows系统上,当type为HGBASE_IMGTYPE_BINARY、HGBASE_IMGTYPE_GRAY、HGBASE_IMGTYPE_BGR或HGBASE_IMGTYPE_BGRA时,新图像内部实际创建DIB位图(有HBITMAP), +* 否则内部分配普通内存(无HBITMAP); 在linux系统上,新图像内部分配普通内存(无HBITMAP) +* 2) 新图像的width=width; 新图像的height=height; 新图像的type=type; 新图像的widthStep为4字节对齐; 新图像的origin=origin +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=96, ydpi=96 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateImage(HGUInt width, HGUInt height, HGUInt type, HGUInt origin, HGImage* image); + +/* 从源数据创建新图像(不分配内存, 也不拷贝数据) +* 参数: +* 1) data: in, 源数据的地址 +* 2) info: in, 源数据的图像信息 +* 3) image: out,新图像句柄 +* 说明: +* 1) 新图像内部不会分配普通像素内存,也不会创建DIB位图(windows系统上, 无HBITMAP),而是直接使用源数据, 在该图像销毁之前需要保证源数据一直有效 +* 2) 新图像的width=info->width; 新图像的height=info->height; 新图像的type=info->type; 新图像的widthStep=info->widthStep; +* 新图像的origin=info->origin +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=96, ydpi=96 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateImageWithData(HGByte* data, const HGImageInfo* info, HGImage* image); + +/* 从源数据创建新图像 +* 参数: +* 1) data: in, 源数据的地址 +* 2) info: in, 源数据的图像信息 +* 3) roi: in, 源数据的感兴趣区域, NULL表示整个图像区域 +* 4) type: in, 新图像的类型, 0表示和源数据一样 +* 5) origin: in, 新图像的数据排列方式, 0表示和源数据一样 +* 6) image: out,新图像句柄 +* 说明: +* 1)在windows系统上,当type为HGBASE_IMGTYPE_BINARY、HGBASE_IMGTYPE_GRAY、HGBASE_IMGTYPE_BGR或HGBASE_IMGTYPE_BGRA时,新图像内部实际创建DIB位图(有HBITMAP), +* 否则内部分配普通内存(无HBITMAP); 在linux系统上,新图像内部分配普通内存(无HBITMAP) +* 2) 新图像的width=roi->right-roi->left; 新图像的height=roi->bottom-roi->top; 新图像的type=type; 新图像的widthStep为4字节对齐; +* 新图像的origin=origin, 如果origin和info->origin不一致,拷贝时像素会进行上下翻转 +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=96, ydpi=96 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateImageFromData(HGByte* data, const HGImageInfo *info, const HGImageRoi *roi, + HGUInt type, HGUInt origin, HGImage* image); + +#if defined(HG_CMP_MSC) + +/* 从DIB位图创建新图像 +* 参数: +* 1) hBmp: in, DIB位图句柄 +* 2) roi: DIB位图的感兴趣区域, NULL表示整个图像区域 +* 3) type: in, 新图像的类型, 0表示自动生成和DIB位图最接近的type +* 4) origin: in, 新图像的数据排列方式, 必须指定 +* 5) image: out,新图像句柄 +* 说明: +* 1)当type为HGBASE_IMGTYPE_BINARY、HGBASE_IMGTYPE_GRAY、HGBASE_IMGTYPE_BGR或HGBASE_IMGTYPE_BGRA时,新图像内部实际创建DIB位图(有HBITMAP), +* 否则内部分配普通内存(无HBITMAP) +* 2) 新图像的width=roi->right-roi->left; 新图像的height=roi->bottom-roi->top; 新图像的type=type; 新图像的widthStep为4字节对齐; +* 新图像的origin=origin +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=hBmp的xDPI, ydpi=hBmp的yDPI +*/ +HGEXPORT HGResult HGAPI HGBase_CreateImageFromHBITMAP(HBITMAP hBmp, const HGImageRoi* roi, + HGUInt type, HGUInt origin, HGImage* image); + +/* 从DIB内存创建新图像 +* 参数: +* 1) hMem: in, DIB内存句柄 +* 2) roi: DIB内存的感兴趣区域, NULL表示整个图像区域 +* 3) type: in, 新图像的类型, 0表示自动生成和DIB内存最接近的type +* 4) origin: in, 新图像的数据排列方式, 必须指定 +* 5) image: out,新图像句柄 +* 说明: +* 1)当type为HGBASE_IMGTYPE_BINARY、HGBASE_IMGTYPE_GRAY、HGBASE_IMGTYPE_BGR或HGBASE_IMGTYPE_BGRA时,新图像内部实际创建DIB位图(有HBITMAP), +* 否则内部分配普通内存(无HBITMAP) +* 2) 新图像的width=roi->right-roi->left; 新图像的height=roi->bottom-roi->top; 新图像的type=type; 新图像的widthStep为4字节对齐; +* 新图像的origin=origin +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=DIB的xDPI, ydpi=DIB的yDPI +*/ +HGEXPORT HGResult HGAPI HGBase_CreateImageFromDIB(HGLOBAL hMem, const HGImageRoi* roi, + HGUInt type, HGUInt origin, HGImage* image); + +#endif /* HG_CMP_MSC */ + +/* 从源图像创建新图像 +* 参数: +* 1) srcImage: in, 源图像 +* 2) type: in, 新图像的类型, 0表示和源图像一样 +* 3) origin: in, 新图像的数据排列方式, 0表示和源图像一样 +* 4) image: out,新图像句柄 +* 说明: +* 1)在windows系统上,当type为HGBASE_IMGTYPE_BINARY、HGBASE_IMGTYPE_GRAY、HGBASE_IMGTYPE_BGR或HGBASE_IMGTYPE_BGRA时,新图像内部实际创建DIB位图(有HBITMAP), +* 否则内部分配普通内存(无HBITMAP); 在linux系统上,新图像内部分配普通内存(无HBITMAP) +* 2) 新图像的width=srcImage->roi.right-srcImage->roi.left; 新图像的height=srcImage->roi.bottom-srcImage->roi.top; +* 新图像的type=type; 新图像的widthStep为4字节对齐; 新图像的origin=origin, 如果origin和srcImage->origin不一致,拷贝时像素会进行上下翻转 +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=srcImage->xdpi, ydpi=srcImage->ydpi +*/ +HGEXPORT HGResult HGAPI HGBase_CloneImage(HGImage srcImage, HGUInt type, HGUInt origin, HGImage* image); + +/* 销毁图像 +* 参数: +* 1) image: in, 图像句柄 +* 说明: +* 1) 如果图像内部分配了像素内存, 销毁图像的同时会自动释放 +* 2) 如果图像内部创建了DIB位图(windows上), 销毁图像的同时会自动调用DeleteObject进行销毁 +* 3) 如果图像内存没有分配内存,也没有创建DIB位图,而是直接使用源数据,销毁图像后源数据才可以释放 +*/ +HGEXPORT HGResult HGAPI HGBase_DestroyImage(HGImage image); + +/* 获取图像数据地址 +* 参数: +* 1) image: in, 图像句柄 +* 2) data: out, 数据地址 +* 说明: +* 1) 如果图像内部分配了内存, 返回的是分配的内存地址 +* 2) 如果图像内部创建了DIB位图,返回的是DIB位图像素数据的内存地址 +* 3) 否则,返回的是源数据地址 +*/ +HGEXPORT HGResult HGAPI HGBase_GetImageData(HGImage image, HGByte** data); + +/* 获取图像信息 +* 参数: +* 1) image: in, 图像句柄 +* 2) info: out, 图像信息 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_GetImageInfo(HGImage image, HGImageInfo* info); + +/* 获取图像感兴趣区域 +* 参数: +* 1) image: in, 图像句柄 +* 2) roi: out, 图像感兴趣区域 +* 说明: +* 1) 默认的感兴趣区域整张图, 即left=0,top=0,right=width,bottom=height +* 2) 图像算法模块可以仅处理感兴趣区域 +*/ +HGEXPORT HGResult HGAPI HGBase_GetImageROI(HGImage image, HGImageRoi* roi); + +/* 设置图像感兴趣区域 +* 参数: +* 1) image: in, 图像句柄 +* 2) roi: in, 图像感兴趣区域 +* 说明: +* 1) roi所指定的区域必须是整个图像幅面的子集 +*/ +HGEXPORT HGResult HGAPI HGBase_SetImageROI(HGImage image, const HGImageRoi* roi); + +/* 重置图像感兴趣区域 +* 参数: +* 1) image: in, 图像句柄 +* 说明: +* 1) 默认的感兴趣区域整张图, 即left=0,top=0,right=width,bottom=height +*/ +HGEXPORT HGResult HGAPI HGBase_ResetImageROI(HGImage image); + +/* 获取图像DPI +* 参数: +* 1) image: in, 图像句柄 +* 2) xDpi: out, xdpi +* 3) yDpi: out, ydpi +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_GetImageDpi(HGImage image, HGUInt *xDpi, HGUInt* yDpi); + +/* 设置图像DPI +* 参数: +* 1) image: in, 图像句柄 +* 2) xDpi: in, xdpi +* 3) yDpi: in, ydpi +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_SetImageDpi(HGImage image, HGUInt xDpi, HGUInt yDpi); + +#if defined(HG_CMP_MSC) + +/* 获取图像内部的DIB位图句柄 +* 参数: +* 1) image: in, 图像句柄 +* 2) hBmp: out, DIB位图句柄 +* 说明: +* 1) 该函数只对windows平台有效 +* 2) 返回的HBITMAP不能用DeleteObject销毁 +*/ +HGEXPORT HGResult HGAPI HGBase_GetHBITMAPOfImage(HGImage image, HBITMAP *hBmp); + +/* 创建DIB位图 +* 参数: +* 1) image: in, 图像句柄 +* 2) hBmp: out, DIB位图句柄 +* 说明: +* 1) 该函数只对windows平台有效 +* 2) 返回的hBmp必须用DeleteObject销毁 +* 3) 操作的只是图像的ROI区域 +* 4) HGBASE_IMGTYPE_RGB会自动转为BGR排列, HGBASE_IMGTYPE_RGBA会自动转为BGRA排列 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateHBITMAPFromImage(HGImage image, HBITMAP* hBmp); + +/* 创建DIB内存 +* 参数: +* 1) image: in, 图像句柄 +* 2) hMem: out, DIB内存句柄 +* 说明: +* 1) 该函数只对windows平台有效 +* 2) 返回的hMem必须用GlobalFree销毁 +* 3) 操作的只是图像的ROI区域 +* 4) HGBASE_IMGTYPE_RGB会自动转为BGR排列, HGBASE_IMGTYPE_RGBA会自动转为BGRA排列 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateDIBFromImage(HGImage image, HGLOBAL* hMem); + +#endif /* HG_CMP_MSC */ + +/* 图像左右镜像 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageMirror(HGImage image, HGImage destImage); + +/* 图像上下镜像 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageFlip(HGImage image, HGImage destImage); + +/* 图像左转 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须宽高互反 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage不能是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageRotateLeft(HGImage image, HGImage destImage); + +/* 图像右转 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须宽高互反 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage不能是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageRotateRight(HGImage image, HGImage destImage); + +/* 图像左转后再左右镜像 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须宽高互反 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage不能是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageRotateLeftMirror(HGImage image, HGImage destImage); + +/* 图像右转后再左右镜像 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须宽高互反 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage不能是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageRotateRightMirror(HGImage image, HGImage destImage); + +/* 图像旋转180度 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageRotate180(HGImage image, HGImage destImage); + +/* 图像灰度化 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageGrayscale(HGImage image, HGImage destImage); + +/* 图像反色 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ReverseImage(HGImage image, HGImage destImage); + +/* 拷贝图像 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 拷贝的时候会自动处理type不一致的情况 +* 3) 拷贝的时候自动处理origin不一致的情况 +* 4) image和destImage不能是同一个图像句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_CopyImage(HGImage image, HGImage destImage); + +#endif /* __HGIMAGE_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGInc.h b/app/modules/base/HGInc.h new file mode 100644 index 0000000..f8ee028 --- /dev/null +++ b/app/modules/base/HGInc.h @@ -0,0 +1,39 @@ +#ifndef __HGINC_H__ +#define __HGINC_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(HG_CMP_MSC) +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#endif /* __HGINC_H__ */ diff --git a/app/modules/base/HGInfo.cpp b/app/modules/base/HGInfo.cpp new file mode 100644 index 0000000..c6e47ff --- /dev/null +++ b/app/modules/base/HGInfo.cpp @@ -0,0 +1,35 @@ +#include "HGInfo.h" +#include "HGInfoImpl.hpp" +#include "HGInc.h" + +HGInfoImpl* g_infoImpl = NULL; + +HGResult HGAPI HGBase_EnableInfo() +{ + if (NULL == g_infoImpl) + return HGBASE_ERR_FAIL; + + return g_infoImpl->Enable(); +} + +HGResult HGAPI HGBase_DisableInfo() +{ + if (NULL == g_infoImpl) + return HGBASE_ERR_FAIL; + + return g_infoImpl->Disable(); +} + +HGResult HGAPIV HGBase_WriteInfo(HGUInt type, const HGChar* format, ...) +{ + if (NULL == g_infoImpl) + return HGBASE_ERR_FAIL; + + char buf[1024] = { 0 }; + va_list va; + va_start(va, format); + vsnprintf(buf, 1024, format, va); + va_end(va); + + return g_infoImpl->Write(type, buf); +} \ No newline at end of file diff --git a/app/modules/base/HGInfo.h b/app/modules/base/HGInfo.h new file mode 100644 index 0000000..7526647 --- /dev/null +++ b/app/modules/base/HGInfo.h @@ -0,0 +1,36 @@ +#ifndef __HGINFO_H__ +#define __HGINFO_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* 致命错误 */ +#define HGBASE_INFOTYPE_FATAL 1L +/* 一般错误 */ +#define HGBASE_INFOTYPE_ERROR 2L +/* 警告 */ +#define HGBASE_INFOTYPE_WARNING 4L +/* 一般描述信息 */ +#define HGBASE_INFOTYPE_DESC 8L +/* 调试信息 */ +#define HGBASE_INFOTYPE_DEBUG 16L + +/* 启用日志/控制台信息 +*/ +HGEXPORT HGResult HGAPI HGBase_EnableInfo(); + +/* 禁用日志/控制台信息 +*/ +HGEXPORT HGResult HGAPI HGBase_DisableInfo(); + +/* 写日志/控制台信息 +* 参数: +* 1) type: in, 信息类型, 参见HGBASE_INFOTYPE_* +* 2) format: in, 信息格式 +* 说明: +* 1) 信息的完整输出行: [日期-时间] [进程号/线程号] [信息类型] [信息] +* 2) 信息的实际输出行取决于config.ini的配置 +*/ +HGEXPORT HGResult HGAPIV HGBase_WriteInfo(HGUInt type, const HGChar* format, ...); + +#endif /* __HGINFO_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGInfoImpl.cpp b/app/modules/base/HGInfoImpl.cpp new file mode 100644 index 0000000..50d57ae --- /dev/null +++ b/app/modules/base/HGInfoImpl.cpp @@ -0,0 +1,171 @@ +#include "HGInfoImpl.hpp" +#include "HGInfo.h" +#include "HGInc.h" +#include "HGUtility.h" +#include "HGIni.h" +#include +#include + +HGInfoImpl::HGInfoImpl() +{ + HGBase_CreateLock(&m_lock); + m_enabled = HGFALSE; + m_log = NULL; + m_console = NULL; + m_type = 0; + m_showTime = HGFALSE; + m_showId = HGFALSE; + m_showType = HGFALSE; + + Enable(); +} + +HGInfoImpl::~HGInfoImpl() +{ + Disable(); + + HGBase_DestroyLock(m_lock); + m_lock = NULL; +} + +HGResult HGInfoImpl::Enable() +{ + if (m_enabled) + { + return HGBASE_ERR_FAIL; + } + + HGChar cfgPath[256] = { 0 }; + HGBase_GetConfigPath(cfgPath, 256); + strcat(cfgPath, "config.ini"); + + HGBool writeLog; + HGBase_GetProfileInt(cfgPath, "info", "writeLog", 1, &writeLog); + HGBool writeConsole; + HGBase_GetProfileInt(cfgPath, "info", "writeConsole", 0, &writeConsole); + HGUInt defType = HGBASE_INFOTYPE_FATAL | HGBASE_INFOTYPE_ERROR | HGBASE_INFOTYPE_WARNING; + HGBase_GetProfileInt(cfgPath, "info", "type", (HGInt)defType, (HGInt*)&m_type); + HGBase_GetProfileInt(cfgPath, "info", "showTime", 1, &m_showTime); + HGBase_GetProfileInt(cfgPath, "info", "showId", 0, &m_showId); + HGBase_GetProfileInt(cfgPath, "info", "showType", 1, &m_showType); + + if (writeLog) + { + HGChar logPath[256]; + HGBase_GetLogFilePath(logPath, 256); + HGBase_CreateDir(logPath); + + timeb tb; + ftime(&tb); + struct tm* p = localtime(&tb.time); + + char fileName[256]; +#if defined(HG_CMP_MSC) + sprintf(fileName, "\\%04d%02d%02d.log", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday); +#else + sprintf(fileName, "/%04d%02d%02d.log", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday); +#endif + strcat(logPath, fileName); + HGBase_OpenLog(logPath, &m_log); + } + + if (writeConsole) + { + HGBase_OpenConsole(&m_console); + } + + m_enabled = HGTRUE; + return HGBASE_ERR_OK; +} + +HGResult HGInfoImpl::Disable() +{ + if (!m_enabled) + { + return HGBASE_ERR_FAIL; + } + + HGBase_CloseConsole(m_console); + m_console = NULL; + HGBase_CloseLog(m_log); + m_log = NULL; + + m_enabled = HGFALSE; + return HGBASE_ERR_OK; +} + +HGResult HGInfoImpl::Write(HGUInt type, const HGChar* info) +{ + if (!m_enabled) + { + return HGBASE_ERR_FAIL; + } + + if (HGBASE_INFOTYPE_FATAL != type && HGBASE_INFOTYPE_ERROR != type + && HGBASE_INFOTYPE_WARNING != type && HGBASE_INFOTYPE_DESC != type + && HGBASE_INFOTYPE_DEBUG != type) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL == info || '\0' == *info) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == (type & m_type)) + { + return HGBASE_ERR_FAIL; + } + + char writeInfo[2048] = { 0 }; + + if (m_showTime) + { + timeb tb; + ftime(&tb); + struct tm* p = localtime(&tb.time); + char timeStr[64] = { 0 }; + sprintf(timeStr, "[%04d/%02d/%02d-%02d:%02d:%02d.%03d]", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec, tb.millitm); + strcat(writeInfo, timeStr); + strcat(writeInfo, " "); + } + + if (m_showId) + { + char idStr[32] = { 0 }; +#if defined(HG_CMP_MSC) + sprintf(idStr, "[0x%08X/0x%08X]", GetCurrentProcessId(), GetCurrentThreadId()); +#else + sprintf(idStr, "[0x%08X/0x%08X]", (HGUInt)getpid(), (HGUInt)syscall(SYS_gettid)); +#endif + strcat(writeInfo, idStr); + strcat(writeInfo, " "); + } + + if (m_showType) + { + char typeStr[24] = { 0 }; + if (HGBASE_INFOTYPE_FATAL == type) + sprintf(typeStr, "[%s]", "FAT"); + else if (HGBASE_INFOTYPE_ERROR == type) + sprintf(typeStr, "[%s]", "ERR"); + else if (HGBASE_INFOTYPE_WARNING == type) + sprintf(typeStr, "[%s]", "WAR"); + else if (HGBASE_INFOTYPE_DESC == type) + sprintf(typeStr, "[%s]", "DES"); + else + sprintf(typeStr, "[%s]", "DEB"); + strcat(writeInfo, typeStr); + strcat(writeInfo, " "); + } + + strcat(writeInfo, info); + + HGBase_EnterLock(m_lock); + HGBase_WriteLog(m_log, writeInfo); + HGBase_WriteConsole(m_console, writeInfo); + HGBase_LeaveLock(m_lock); + return HGBASE_ERR_OK; +} diff --git a/app/modules/base/HGInfoImpl.hpp b/app/modules/base/HGInfoImpl.hpp new file mode 100644 index 0000000..956dd4e --- /dev/null +++ b/app/modules/base/HGInfoImpl.hpp @@ -0,0 +1,29 @@ +#ifndef __HGINFOIMPL_HPP__ +#define __HGINFOIMPL_HPP__ + +#include "HGLog.h" +#include "HGConsole.h" +#include "HGLock.h" + +class HGInfoImpl +{ +public: + HGInfoImpl(); + ~HGInfoImpl(); + + HGResult Enable(); + HGResult Disable(); + HGResult Write(HGUInt type, const HGChar* info); + +private: + HGLock m_lock; + HGBool m_enabled; + HGLog m_log; + HGConsole m_console; + HGUInt m_type; + HGBool m_showTime; + HGBool m_showId; + HGBool m_showType; +}; + +#endif /* __HGINFOIMPL_HPP__ */ \ No newline at end of file diff --git a/app/modules/base/HGIni.cpp b/app/modules/base/HGIni.cpp new file mode 100644 index 0000000..67b1313 --- /dev/null +++ b/app/modules/base/HGIni.cpp @@ -0,0 +1,339 @@ +#include "HGIni.h" +#include "HGInc.h" +#include "HGInfo.h" +#include +#include + +static HGUInt IniWriteValue(const char* section, const char* key, const char* val, const char* file) +{ + typedef std::vector > KeyList; + typedef std::vector > SectionList; + + SectionList sectList; + + FILE* fp = fopen(file, "r"); + if (fp != NULL) + { + KeyList* pCurKeyList = NULL; + + while (feof(fp) == 0) + { + char lineContent[256] = { 0 }; + if (NULL == fgets(lineContent, 256, fp)) + { + continue; + } + + if ((lineContent[0] == ';') || (lineContent[0] == '\0') || (lineContent[0] == '\r') || (lineContent[0] == '\n')) + { + continue; + } + + for (size_t i = 0; i < strlen(lineContent); ++i) + { + if (lineContent[i] == '\r' || lineContent[i] == '\n') + { + lineContent[i] = '\0'; + break; + } + } + + if (lineContent[0] == '[') + { + std::pair pr; + pr.first = lineContent; + sectList.push_back(pr); + pCurKeyList = §List[sectList.size() - 1].second; + } + else + { + int pos = -1; + for (int i = 0; i < (int)strlen(lineContent); ++i) + { + if (lineContent[i] == '=') + { + pos = i; + break; + } + } + + if (NULL != pCurKeyList) + { + std::pair pr; + if (-1 != pos) + { + pr.first.assign(lineContent, pos); + pr.second.assign(lineContent + pos + 1); + } + else + { + pr.first = lineContent; + } + + pCurKeyList->push_back(pr); + } + } + } + + fclose(fp); + } + + bool bFindSect = false; + for (size_t i = 0; i < sectList.size(); ++i) + { + if (strcmp(sectList[i].first.c_str(), section) == 0) + { + bool bFindKey = false; + for (size_t j = 0; j < sectList[i].second.size(); ++j) + { + if (strcmp(sectList[i].second[j].first.c_str(), key) == 0) + { + sectList[i].second[j].second = val; + bFindKey = true; + break; + } + } + + if (!bFindKey) + { + std::pair pr; + pr.first = key; + pr.second = val; + sectList[i].second.push_back(pr); + } + + bFindSect = true; + break; + } + } + + if (!bFindSect) + { + std::pair pr; + pr.first = section; + std::pair pr2; + pr2.first = key; + pr2.second = val; + pr.second.push_back(pr2); + sectList.push_back(pr); + } + + fp = fopen(file, "w"); + if (fp == NULL) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "IniWriteValue: fopen fail %s errno=%d", file, errno); + return HGBASE_ERR_ACCESSDENIED; + } + + for (size_t i = 0; i < sectList.size(); ++i) + { + fputs(sectList[i].first.c_str(), fp); + fputs("\n", fp); + + for (size_t j = 0; j < sectList[i].second.size(); ++j) + { + fputs(sectList[i].second[j].first.c_str(), fp); + fputs("=", fp); + fputs(sectList[i].second[j].second.c_str(), fp); + fputs("\n", fp); + } + } + + fclose(fp); + return HGBASE_ERR_OK; +} + +static HGResult writeStringValue(const char* section, const char* key, const char* val, const char* file) +{ + if (section == NULL || key == NULL || val == NULL || file == NULL) + { + return HGBASE_ERR_INVALIDARG; + } + + char sect[256]; + sprintf(sect, "[%s]", section); + return IniWriteValue(sect, key, val, file); +} + +HGResult HGAPI HGBase_SetProfileInt(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, HGInt value) +{ + if (NULL == fileName || NULL == appName || NULL == keyName) + { + return HGBASE_ERR_INVALIDARG; + } + + char str[8]; + sprintf(str, "%d", value); + return writeStringValue(appName, keyName, str, fileName); +} + +HGResult HGAPI HGBase_SetProfileString(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, const HGChar* value) +{ + if (NULL == fileName || NULL == appName || NULL == keyName) + { + return HGBASE_ERR_INVALIDARG; + } + + return writeStringValue(appName, keyName, value, fileName); +} + +static HGResult IniReadValue(const char* section, const char* key, char* val, const char* def, const char* file) +{ + typedef std::vector > KeyList; + typedef std::vector > SectionList; + + SectionList sectList; +#if defined(HG_CMP_MSC) + if (0 != _access(file, 0)) +#else + if (0 != access(file, 0)) +#endif + { + return HGBASE_ERR_FILENOTEXIST; + } + + FILE* fp = fopen(file, "r"); + if (fp != NULL) + { + KeyList* pCurKeyList = NULL; + + while (feof(fp) == 0) + { + char lineContent[256] = { 0 }; + if (NULL == fgets(lineContent, 256, fp)) + { + continue; + } + + if ((lineContent[0] == ';') || (lineContent[0] == '\0') || (lineContent[0] == '\r') || (lineContent[0] == '\n')) + { + continue; + } + + for (size_t i = 0; i < strlen(lineContent); ++i) + { + if (lineContent[i] == '\r' || lineContent[i] == '\n') + { + lineContent[i] = '\0'; + break; + } + } + + if (lineContent[0] == '[') + { + std::pair pr; + pr.first = lineContent; + sectList.push_back(pr); + pCurKeyList = §List[sectList.size() - 1].second; + } + else + { + int pos = -1; + for (int i = 0; i < (int)strlen(lineContent); ++i) + { + if (lineContent[i] == '=') + { + pos = i; + break; + } + } + + if (NULL != pCurKeyList) + { + std::pair pr; + if (-1 != pos) + { + pr.first.assign(lineContent, pos); + pr.second.assign(lineContent + pos + 1); + } + else + { + pr.first = lineContent; + } + + pCurKeyList->push_back(pr); + } + } + } + + fclose(fp); + } + else + { + strcpy(val, def); + return HGBASE_ERR_ACCESSDENIED; + } + + bool bGetVal = false; + for (size_t i = 0; i < sectList.size(); ++i) + { + if (strcmp(sectList[i].first.c_str(), section) == 0) + { + for (size_t j = 0; j < sectList[i].second.size(); ++j) + { + if (strcmp(sectList[i].second[j].first.c_str(), key) == 0) + { + strcpy(val, sectList[i].second[j].second.c_str()); + bGetVal = true; + break; + } + } + + break; + } + } + + if (!bGetVal) + { + strcpy(val, def); + } + + return HGBASE_ERR_OK; +} + +static HGResult readStringValue(const char* section, const char* key, char* val, const char* def, const char* file) +{ + if (section == NULL || key == NULL || val == NULL || def == NULL || file == NULL) + { + return HGBASE_ERR_INVALIDARG; + } + + char sect[256]; + sprintf(sect, "[%s]", section); + return IniReadValue(sect, key, val, def, file); +} + +HGResult HGAPI HGBase_GetProfileInt(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, HGInt def, HGInt* value) +{ + if (NULL == appName || NULL == keyName || NULL == value) + { + return HGBASE_ERR_INVALIDARG; + } + + char strRet[256] = { 0 }; + char strDef[32]; + sprintf(strDef, "%d", def); + HGResult ret = readStringValue(appName, keyName, strRet, strDef, fileName); + if (HGBASE_ERR_OK != ret) + { + *value = def; + return ret; + } + + *value = atoi(strRet); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetProfileString(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, const HGChar* def, HGChar* value, HGUInt maxLen) +{ + if (NULL == appName || NULL == keyName || NULL == value) + { + return HGBASE_ERR_INVALIDARG; + } + + return readStringValue(appName, keyName, value, def, fileName); +} diff --git a/app/modules/base/HGIni.h b/app/modules/base/HGIni.h new file mode 100644 index 0000000..82cc2c8 --- /dev/null +++ b/app/modules/base/HGIni.h @@ -0,0 +1,27 @@ +#ifndef __HGINI_H__ +#define __HGINI_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* 设置ini文件的值 +*/ +HGEXPORT HGResult HGAPI HGBase_SetProfileInt(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, HGInt value); + +/* 设置ini文件的值 +*/ +HGEXPORT HGResult HGAPI HGBase_SetProfileString(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, const HGChar* value); + +/* 获取ini文件的值 +*/ +HGEXPORT HGResult HGAPI HGBase_GetProfileInt(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, HGInt def, HGInt* value); + +/* 获取ini文件的值 +*/ +HGEXPORT HGResult HGAPI HGBase_GetProfileString(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, const HGChar* def, HGChar* value, HGUInt maxLen); + +#endif /* __HGINI_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGLock.cpp b/app/modules/base/HGLock.cpp new file mode 100644 index 0000000..e677140 --- /dev/null +++ b/app/modules/base/HGLock.cpp @@ -0,0 +1,78 @@ +#include "HGLock.h" +#include "HGInc.h" + +HGResult HGAPI HGBase_CreateLock(HGLock* lock) +{ + if (NULL == lock) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + pthread_mutex_t* hLock = new pthread_mutex_t; + if (0 != pthread_mutex_init(hLock, NULL)) + { + delete hLock; + return HGBASE_ERR_FAIL; + } + *lock = (HGLock)hLock; +#else + CRITICAL_SECTION* hLock = new CRITICAL_SECTION; + InitializeCriticalSection(hLock); + *lock = (HGLock)hLock; +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_DestroyLock(HGLock lock) +{ + if (NULL == lock) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + pthread_mutex_t* hLock = (pthread_mutex_t*)lock; + pthread_mutex_destroy(hLock); + delete hLock; +#else + CRITICAL_SECTION* hLock = (CRITICAL_SECTION*)lock; + DeleteCriticalSection(hLock); + delete hLock; +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_EnterLock(HGLock lock) +{ + if (NULL == lock) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + pthread_mutex_t* hLock = (pthread_mutex_t*)lock; + pthread_mutex_lock(hLock); +#else + CRITICAL_SECTION* hLock = (CRITICAL_SECTION*)lock; + EnterCriticalSection(hLock); +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_LeaveLock(HGLock lock) +{ + if (NULL == lock) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + pthread_mutex_t* hLock = (pthread_mutex_t*)lock; + pthread_mutex_unlock(hLock); +#else + CRITICAL_SECTION* hLock = (CRITICAL_SECTION*)lock; + LeaveCriticalSection(hLock); +#endif + return HGBASE_ERR_OK; +} diff --git a/app/modules/base/HGLock.h b/app/modules/base/HGLock.h new file mode 100644 index 0000000..128d03b --- /dev/null +++ b/app/modules/base/HGLock.h @@ -0,0 +1,37 @@ +#ifndef __HGLOCK_H__ +#define __HGLOCK_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGLock); + +/* 创建互斥锁 +* 参数: +* 1) lock: out, 互斥锁句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_CreateLock(HGLock* lock); + +/* 销毁互斥锁 +* 参数: +* 1) lock: in, 互斥锁句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_DestroyLock(HGLock lock); + +/* 加锁 +* 参数: +* 1) lock: in, 互斥锁句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_EnterLock(HGLock lock); + +/* 解锁 +* 参数: +* 1) lock: in, 互斥锁句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_LeaveLock(HGLock lock); + +#endif /* __HGLOCK_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGLog.cpp b/app/modules/base/HGLog.cpp new file mode 100644 index 0000000..8825f98 --- /dev/null +++ b/app/modules/base/HGLog.cpp @@ -0,0 +1,89 @@ +#include "HGLog.h" +#include "HGInc.h" + +struct HGLogImpl +{ + HGLogImpl() + { + m_file = NULL; + } + + ~HGLogImpl() + { + if (NULL != m_file) + { + fclose(m_file); + m_file = NULL; + } + } + + FILE* m_file; +}; + +HGResult HGAPI HGBase_OpenLog(const HGChar* fileName, HGLog* log) +{ + if (NULL == fileName || NULL == log) + { + return HGBASE_ERR_INVALIDARG; + } + + FILE *file = fopen(fileName, "a+"); + if (NULL == file) + { + return HGBASE_ERR_ACCESSDENIED; + } + + HGLogImpl* logImpl = new HGLogImpl; + logImpl->m_file = file; + *log = (HGLog)logImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CloseLog(HGLog log) +{ + if (NULL == log) + { + return HGBASE_ERR_INVALIDARG; + } + + HGLogImpl* logImpl = (HGLogImpl*)log; + delete logImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetLogFileSize(HGLog log, HGLonglong* size) +{ + if (NULL == log || NULL == size) + { + return HGBASE_ERR_INVALIDARG; + } + + HGLogImpl* logImpl = (HGLogImpl*)log; +#if defined(HG_CMP_MSC) + _fseeki64(logImpl->m_file, 0, SEEK_END); + *size = _ftelli64(logImpl->m_file); +#else + fseeko64(logImpl->m_file, 0, SEEK_END); + *size = ftello64(logImpl->m_file); +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_WriteLog(HGLog log, const HGChar* info) +{ + if (NULL == log || NULL == info || '\0' == *info) + { + return HGBASE_ERR_INVALIDARG; + } + + HGLogImpl* logImpl = (HGLogImpl*)log; +#if defined(HG_CMP_MSC) + _fseeki64(logImpl->m_file, 0, SEEK_END); +#else + fseeko64(logImpl->m_file, 0, SEEK_END); +#endif + fwrite(info, 1, strlen(info), logImpl->m_file); + fwrite("\n", 1, strlen("\n"), logImpl->m_file); + fflush(logImpl->m_file); + return HGBASE_ERR_OK; +} \ No newline at end of file diff --git a/app/modules/base/HGLog.h b/app/modules/base/HGLog.h new file mode 100644 index 0000000..fa18a71 --- /dev/null +++ b/app/modules/base/HGLog.h @@ -0,0 +1,42 @@ +#ifndef __HGLOG_H__ +#define __HGLOG_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGLog); + +/* 开启日志 +* 参数: +* 1) fileName: in, 文件名 +* 2) log: out, 日志句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_OpenLog(const HGChar* fileName, HGLog* log); + +/* 关闭日志 +* 参数: +* 1) log: in, 日志句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_CloseLog(HGLog log); + +/* 获取日志文件大小 +* 参数: +* 1) log: in, 日志句柄 +* 2) size: out, 日志文件大小 +* 说明: +* 1) 每次写入日志信息后,可以用该函数检查日志文件的大小,当日志文件足够大时,可以关闭该日志句柄,在新的日志文件上重新打开 +*/ +HGEXPORT HGResult HGAPI HGBase_GetLogFileSize(HGLog log, HGLonglong* size); + +/* 写日志信息 +* 参数: +* 1) log: in, 日志句柄 +* 2) info: in, 信息, 一次一行, info无需加换行符 +* 说明: +* 1) 该函数不是线程安全的, 在不同进程或不同线程调用的时候, 需要加锁 +*/ +HGEXPORT HGResult HGAPI HGBase_WriteLog(HGLog log, const HGChar* info); + +#endif /* __HGLOG_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGMd5.cpp b/app/modules/base/HGMd5.cpp new file mode 100644 index 0000000..e6469cf --- /dev/null +++ b/app/modules/base/HGMd5.cpp @@ -0,0 +1,314 @@ +#include "HGMd5.h" +#include "HGInc.h" + +/* Constants for MD5Transform routine. */ +/* md5转换用到的常量,算法本身规定的 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +/* + 接下来的这几个宏定义是md5算法规定的,就是对信息进行md5加密都要做的运算。 + 据说有经验的高手跟踪程序时根据这几个特殊的操作就可以断定是不是用的md5 + F, G, H and I are basic MD5 functions. +*/ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* + ROTATE_LEFT rotates x left n bits. +*/ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* + FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent recomputation. +*/ +#define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (HGUInt)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } +#define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (HGUInt)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } +#define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (HGUInt)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } +#define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (HGUInt)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } + +/* MD5 context. */ +struct MD5_CTX +{ + /* state (ABCD) */ + /*四个32bits数,用于存放最终计算得到的消息摘要。当消息长度〉512bits时,也用于存放每个512bits的中间结果*/ + HGUInt state[4]; + /* number of bits, modulo 2^64 (lsb first) */ + /*存储原始信息的bits数长度,不包括填充的bits,最长为 2^64 bits,因为2^64是一个64位数的最大值*/ + HGUInt count[2]; + /* input buffer */ + /*存放输入的信息的缓冲区,512bits*/ + HGByte buffer[64]; +}; + +/* MD5 initialization. Begins an MD5 operation, writing a new context. */ +/*初始化md5的结构*/ +static void MD5Init(MD5_CTX* ctx) +{ + /*将当前的有效信息的长度设成0,这个很简单,还没有有效信息,长度当然是0了*/ + ctx->count[0] = 0; + ctx->count[1] = 0; + + /* Load magic initialization constants.*/ + /*初始化链接变量,算法要求这样,这个没法解释了*/ + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; +} + +/* + 将4字节的整数copy到字符形式的缓冲区中 + output:用于输出的字符缓冲区 + input:欲转换的四字节的整数形式的数组 + len:output缓冲区的长度,要求是4的整数倍 +*/ +static void MD5Encode(HGByte* output, const HGUInt* input, HGUInt len) +{ + for (HGUInt i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (HGByte)(input[i] & 0xFF); + output[j + 1] = (HGByte)((input[i] >> 8) & 0xFF); + output[j + 2] = (HGByte)((input[i] >> 16) & 0xFF); + output[j + 3] = (HGByte)((input[i] >> 24) & 0xFF); + } +} + +/* + 与上面的函数正好相反,这一个把字符形式的缓冲区中的数据copy到4字节的整数中(即以整数形式保存) + output:保存转换出的整数 + input:欲转换的字符缓冲区 + len:输入的字符缓冲区的长度,要求是4的整数倍 +*/ +static void MD5Decode(HGUInt* output, const HGByte* input, HGUInt len) +{ + for (HGUInt i = 0, j = 0; j < len; i++, j += 4) + { + output[i] = ((HGUInt)input[j]) | (((HGUInt)input[j + 1]) << 8) | (((HGUInt)input[j + 2]) << 16) | (((HGUInt)input[j + 3]) << 24); + } +} + +/* + 对512bits信息(即block缓冲区)进行一次处理,每次处理包括四轮 + state[4]:md5结构中的state[4],用于保存对512bits信息加密的中间结果或者最终结果 + block[64]:欲加密的512bits信息 +*/ +static void MD5Transform(HGUInt* state, const HGByte* block) +{ + HGUInt a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + MD5Decode(x, block, 64); + + /* Round 1 */ + FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset(x, 0, sizeof(x)); +} + +/* + MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + 将与加密的信息传递给md5结构,可以多次调用 + context:初始化过了的md5结构 + input:欲加密的信息,可以任意长 + inputLen:指定input的长度 +*/ +static void MD5Update(MD5_CTX* ctx, const HGByte* data, HGUInt size) +{ + HGUInt i, index, partLen; + + /* + 计算已有信息的bits长度的字节数的模64, 64bytes=512bits。 + 用于判断已有信息加上当前传过来的信息的总长度能不能达到512bits, + 如果能够达到则对凑够的512bits进行一次处理 + */ + index = (HGUInt)((ctx->count[0] >> 3) & 0x3F); + + /* Update number of bits *//*更新已有信息的bits长度 */ + if ((ctx->count[0] += ((HGUInt)size << 3)) < ((HGUInt)size << 3)) + ctx->count[1]++; + ctx->count[1] += ((HGUInt)size >> 29); + + /* 计算已有的字节数长度还差多少字节可以 凑成64的整倍数 */ + partLen = 64 - index; + + /* 如果当前输入的字节数 大于 已有字节数长度补足64字节整倍数所差的字节数 */ + if (size >= partLen) + { + /* 用当前输入的内容把ctx->buffer的内容补足512bits */ + memcpy(&ctx->buffer[index], data, partLen); + /* 用基本函数对填充满的512bits(已经保存到ctx->buffer中) 做一次转换,转换结果保存到ctx->state中 */ + MD5Transform(ctx->state, ctx->buffer); + + /* + 对当前输入的剩余字节做转换(如果剩余的字节<在输入的data缓冲区中>大于512bits的话), + 转换结果保存到ctx->state中 + */ + for (i = partLen; i + 63 < size; i += 64) /* 把i+63state, &data[i]); + + index = 0; + } + else + { + i = 0; + } + + /* 将输入缓冲区中的不足填充满512bits的剩余内容填充到ctx->buffer中,留待以后再作处理 */ + memcpy(&ctx->buffer[index], &data[i], size - i); +} + +/* + MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + 获取加密 的最终结果 + digest:保存最终的加密串 + context:你前面初始化并填入了信息的md5结构 +*/ +static void MD5Final(MD5_CTX* ctx, HGByte* md5) +{ + /* + 用于bits填充的缓冲区,为什么要64个字节呢?因为当欲加密的信息的bits数被512除其余数为448时, + 需要填充的bits的最大值为512=64*8 。 + */ + static const HGByte MD5_PADDING[64] = + { + 0x80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + + HGByte bits[8]; + HGUInt index, padLen; + + /* 将要被转换的信息(所有的)的bits长度拷贝到bits中 */ + MD5Encode(bits, ctx->count, 8); + + /* 计算所有的bits长度的字节数的模64, 64bytes=512bits */ + index = (HGUInt)((ctx->count[0] >> 3) & 0x3F); + + /* 计算需要填充的字节数,padLen的取值范围在1-64之间 */ + padLen = (index < 56) ? (56 - index) : (120 - index); + + /* 这一次函数调用绝对不会再导致MD5Transform的被调用,因为这一次不会填满512bits */ + MD5Update(ctx, MD5_PADDING, padLen); + /* 补上原始信息的bits长度(bits长度固定的用64bits表示),这一次能够恰巧凑够512bits,不会多也不会少 */ + MD5Update(ctx, bits, 8); + + /* Store state in digest */ + MD5Encode(md5, ctx->state, 16); + memset(ctx, 0, sizeof(MD5_CTX)); +} + +HGResult HGAPI HGBase_MakeMd5(const HGByte* data, HGUInt size, HGByte* md5) +{ + if (NULL == data || 0 == size || NULL == md5) + { + return HGBASE_ERR_INVALIDARG; + } + + MD5_CTX ctx; + MD5Init(&ctx); + MD5Update(&ctx, data, size); + MD5Final(&ctx, md5); + + return HGBASE_ERR_OK; +} \ No newline at end of file diff --git a/app/modules/base/HGMd5.h b/app/modules/base/HGMd5.h new file mode 100644 index 0000000..e9406c2 --- /dev/null +++ b/app/modules/base/HGMd5.h @@ -0,0 +1,16 @@ +#ifndef __HGMD5_H__ +#define __HGMD5_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* 生成MD5值 +* 参数: +* 1) data: in, 数据地址 +* 2) size: in, 数据长度 +* 3) md5: out, md5值, 必须至少分配16字节 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_MakeMd5(const HGByte* data, HGUInt size, HGByte* md5); + +#endif /* __HGMD5_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGMsgPump.cpp b/app/modules/base/HGMsgPump.cpp new file mode 100644 index 0000000..b3ba81e --- /dev/null +++ b/app/modules/base/HGMsgPump.cpp @@ -0,0 +1,59 @@ +#include "HGMsgPump.h" +#include "HGMsgPumpImpl.hpp" + +HGResult HGAPI HGBase_CreateMsgPump(HGMsgPump* msgPump) +{ + if (NULL == msgPump) + { + return HGBASE_ERR_INVALIDARG; + } + + HGMsgPumpImpl* msgPumpImpl = new HGMsgPumpImpl; + *msgPump = (HGMsgPump)msgPumpImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_DestroyMsgPump(HGMsgPump msgPump) +{ + if (NULL == msgPump) + { + return HGBASE_ERR_INVALIDARG; + } + + HGMsgPumpImpl* msgPumpImpl = (HGMsgPumpImpl*)msgPump; + delete msgPumpImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_RunMsgPump(HGMsgPump msgPump, HGMsgPumpFunc func, HGPointer param) +{ + if (NULL == msgPump) + { + return HGBASE_ERR_INVALIDARG; + } + + HGMsgPumpImpl* msgPumpImpl = (HGMsgPumpImpl*)msgPump; + return msgPumpImpl->Run(func, param); +} + +HGResult HGAPI HGBase_PostPumpMessage(HGMsgPump msgPump, const HGMsg* msg) +{ + if (NULL == msgPump) + { + return HGBASE_ERR_INVALIDARG; + } + + HGMsgPumpImpl* msgPumpImpl = (HGMsgPumpImpl*)msgPump; + return msgPumpImpl->PostMessage(msg); +} + +HGResult HGAPI HGBase_ExitMsgPump(HGMsgPump msgPump) +{ + if (NULL == msgPump) + { + return HGBASE_ERR_INVALIDARG; + } + + HGMsgPumpImpl* msgPumpImpl = (HGMsgPumpImpl*)msgPump; + return msgPumpImpl->Exit(); +} \ No newline at end of file diff --git a/app/modules/base/HGMsgPump.h b/app/modules/base/HGMsgPump.h new file mode 100644 index 0000000..5ab886c --- /dev/null +++ b/app/modules/base/HGMsgPump.h @@ -0,0 +1,33 @@ +#ifndef __HGMSGPUMP_H__ +#define __HGMSGPUMP_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGMsgPump); + +#pragma pack(push) +#pragma pack(4) + +/* 消息结构体, 可以自定义 */ +typedef struct +{ + HGUInt id; /* 消息ID, 不能为0 */ + HGPointer data; /* 携带的数据 */ +}HGMsg; + +#pragma pack(pop) + +typedef void (HGAPI *HGMsgPumpFunc)(HGMsgPump msgPump, const HGMsg* msg, HGPointer param); + +HGEXPORT HGResult HGAPI HGBase_CreateMsgPump(HGMsgPump *msgPump); + +HGEXPORT HGResult HGAPI HGBase_DestroyMsgPump(HGMsgPump msgPump); + +HGEXPORT HGResult HGAPI HGBase_RunMsgPump(HGMsgPump msgPump, HGMsgPumpFunc func, HGPointer param); + +HGEXPORT HGResult HGAPI HGBase_PostPumpMessage(HGMsgPump msgPump, const HGMsg *msg); + +HGEXPORT HGResult HGAPI HGBase_ExitMsgPump(HGMsgPump msgPump); + +#endif /* __HGMSGPUMP_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGMsgPumpImpl.cpp b/app/modules/base/HGMsgPumpImpl.cpp new file mode 100644 index 0000000..e78cb6a --- /dev/null +++ b/app/modules/base/HGMsgPumpImpl.cpp @@ -0,0 +1,102 @@ +#include "HGMsgPumpImpl.hpp" + +HGMsgPumpImpl::HGMsgPumpImpl() +{ + HGBase_CreateEvent(HGTRUE, HGFALSE, &m_msgEvent); + HGBase_CreateLock(&m_msgLock); + m_bRecvMsg = HGTRUE; +} + +HGMsgPumpImpl::~HGMsgPumpImpl() +{ + HGBase_DestroyLock(m_msgLock); + m_msgLock = NULL; + HGBase_DestroyEvent(m_msgEvent); + m_msgEvent = NULL; +} + +HGResult HGMsgPumpImpl::Run(HGMsgPumpFunc func, HGPointer param) +{ + if (NULL == func) + { + return HGBASE_ERR_INVALIDARG; + } + + while (1) + { + HGBase_WaitEvent(m_msgEvent); + + HGMsg msg = { 0 }; + bool getMsg = false; + + HGBase_EnterLock(m_msgLock); + if (!m_listMsg.empty()) + { + msg = m_listMsg.front(); + m_listMsg.pop_front(); + getMsg = true; + } + if (m_listMsg.empty()) + { + HGBase_ResetEvent(m_msgEvent); + } + HGBase_LeaveLock(m_msgLock); + + if (!getMsg) + { + continue; + } + + if (0 == msg.id) + { + assert(NULL == msg.data); + break; + } + else + { + func((HGMsgPump)this, &msg, param); + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGMsgPumpImpl::PostMessage(const HGMsg* msg) +{ + if (NULL == msg || 0 == msg->id) + { + return HGBASE_ERR_INVALIDARG; + } + + HGResult ret = HGBASE_ERR_FAIL; + HGBase_EnterLock(m_msgLock); + if (m_bRecvMsg) + { + m_listMsg.push_back(*msg); + HGBase_SetEvent(m_msgEvent); + ret = HGBASE_ERR_OK; + } + HGBase_LeaveLock(m_msgLock); + + return ret; +} + +HGResult HGMsgPumpImpl::Exit() +{ + HGMsg msg; + msg.id = 0; + msg.data = NULL; + + HGResult ret = HGBASE_ERR_FAIL; + HGBase_EnterLock(m_msgLock); + if (m_bRecvMsg) + { + m_listMsg.push_back(msg); + HGBase_SetEvent(m_msgEvent); + m_bRecvMsg = HGFALSE; + ret = HGBASE_ERR_OK; + } + HGBase_LeaveLock(m_msgLock); + + return ret; +} \ No newline at end of file diff --git a/app/modules/base/HGMsgPumpImpl.hpp b/app/modules/base/HGMsgPumpImpl.hpp new file mode 100644 index 0000000..1cfb138 --- /dev/null +++ b/app/modules/base/HGMsgPumpImpl.hpp @@ -0,0 +1,28 @@ +#ifndef __HGMSGPUMPIMPL_H__ +#define __HGMSGPUMPIMPL_H__ + +#include "HGDef.h" +#include "HGInc.h" +#include "HGEvent.h" +#include "HGLock.h" +#include "HGMsgPump.h" +#include + +class HGMsgPumpImpl +{ +public: + HGMsgPumpImpl(); + ~HGMsgPumpImpl(); + + HGResult Run(HGMsgPumpFunc func, HGPointer param); + HGResult PostMessage(const HGMsg* msg); + HGResult Exit(); + +private: + HGEvent m_msgEvent; + HGLock m_msgLock; + HGBool m_bRecvMsg; + std::list m_listMsg; +}; + +#endif /* __HGMSGPUMPIMPL_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGNamedPipe.cpp b/app/modules/base/HGNamedPipe.cpp new file mode 100644 index 0000000..db0095d --- /dev/null +++ b/app/modules/base/HGNamedPipe.cpp @@ -0,0 +1,621 @@ +#include "HGNamedPipe.h" +#include "HGInc.h" +#include "HGThread.h" +#include + +struct HGNamedPipeServerImpl +{ + HGNamedPipeServerImpl() + { +#if defined(HG_CMP_MSC) + m_hConnectEvent = NULL; + m_hWriteEvent = NULL; + m_hReadEvent = NULL; + m_hProcessEvent = NULL; + m_hPipe = INVALID_HANDLE_VALUE; + m_clientPid = 0; + m_thread = NULL; + m_error = HGFALSE; + m_break = HGFALSE; +#else + // TODO +#endif + } + + ~HGNamedPipeServerImpl() + { +#if defined(HG_CMP_MSC) + HGBase_CloseThread(m_thread); + m_thread = NULL; + CloseHandle(m_hPipe); + m_hPipe = INVALID_HANDLE_VALUE; + CloseHandle(m_hProcessEvent); + m_hProcessEvent = NULL; + CloseHandle(m_hReadEvent); + m_hReadEvent = NULL; + CloseHandle(m_hWriteEvent); + m_hWriteEvent = NULL; + CloseHandle(m_hConnectEvent); + m_hConnectEvent = NULL; +#else + // TODO +#endif + } + +#if defined(HG_CMP_MSC) + HANDLE m_hConnectEvent; + HANDLE m_hWriteEvent; + HANDLE m_hReadEvent; + HANDLE m_hProcessEvent; + HANDLE m_hPipe; + DWORD m_clientPid; + HGThread m_thread; + HGBool m_error; + HGBool m_break; +#else + // TODO +#endif +}; + +struct HGNamedPipeClientImpl +{ + HGNamedPipeClientImpl() + { +#if defined(HG_CMP_MSC) + m_hWriteEvent = NULL; + m_hReadEvent = NULL; + m_hProcessEvent = NULL; + m_hPipe = INVALID_HANDLE_VALUE; + m_serverPid = 0; + m_thread = NULL; + m_error = HGFALSE; + m_break = HGFALSE; +#else + // TODO +#endif + } + + ~HGNamedPipeClientImpl() + { +#if defined(HG_CMP_MSC) + HGBase_CloseThread(m_thread); + m_thread = NULL; + CloseHandle(m_hPipe); + m_hPipe = INVALID_HANDLE_VALUE; + CloseHandle(m_hProcessEvent); + m_hProcessEvent = NULL; + CloseHandle(m_hReadEvent); + m_hReadEvent = NULL; + CloseHandle(m_hWriteEvent); + m_hWriteEvent = NULL; +#else + // TODO +#endif + } + +#if defined(HG_CMP_MSC) + HANDLE m_hWriteEvent; + HANDLE m_hReadEvent; + HANDLE m_hProcessEvent; + HANDLE m_hPipe; + DWORD m_serverPid; + HGThread m_thread; + HGBool m_error; + HGBool m_break; +#else + // TODO +#endif +}; + +static void HGAPI NamedPipeServerFunc(HGThread thread, HGPointer param) +{ + HGNamedPipeServerImpl* p = (HGNamedPipeServerImpl*)param; +#if defined(HG_CMP_MSC) + HANDLE handles[2]; + handles[0] = OpenProcess(SYNCHRONIZE, FALSE, p->m_clientPid); + handles[1] = p->m_hProcessEvent; + if (WAIT_OBJECT_0 == WaitForMultipleObjects(2, handles, FALSE, INFINITE)) + { + p->m_error = HGTRUE; + SetEvent(p->m_hWriteEvent); + SetEvent(p->m_hReadEvent); + } + + CloseHandle(handles[0]); +#else + // TODO +#endif +} + +static void NamedPipeClientFunc(HGThread thread, HGPointer param) +{ + HGNamedPipeClientImpl* p = (HGNamedPipeClientImpl*)param; +#if defined(HG_CMP_MSC) + HANDLE handles[2]; + handles[0] = OpenProcess(SYNCHRONIZE, FALSE, p->m_serverPid); + handles[1] = p->m_hProcessEvent; + if (WAIT_OBJECT_0 == WaitForMultipleObjects(2, handles, FALSE, INFINITE)) + { + p->m_error = HGTRUE; + SetEvent(p->m_hWriteEvent); + SetEvent(p->m_hReadEvent); + } + + CloseHandle(handles[0]); +#else + // TODO +#endif +} + +HGResult HGAPI HGBase_OpenNamedPipeServer(const HGChar* pipeName, HGNamedPipeServer* server) +{ + if (NULL == pipeName || NULL == server) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + HANDLE hConnectEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + assert(NULL != hConnectEvent); + HANDLE hWriteEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + assert(NULL != hWriteEvent); + HANDLE hReadEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + assert(NULL != hReadEvent); + HANDLE hProcessEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + assert(NULL != hProcessEvent); + + char name[256]; + sprintf(name, "\\\\.\\pipe\\%s", pipeName); + HANDLE hPipe = CreateNamedPipeA(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, + 0, 1, 1024, 1024, 0, NULL); + if (INVALID_HANDLE_VALUE == hPipe) + { + CloseHandle(hProcessEvent); + CloseHandle(hReadEvent); + CloseHandle(hWriteEvent); + CloseHandle(hConnectEvent); + return HGBASE_ERR_FAIL; + } + + HGNamedPipeServerImpl* pipeServerImpl = new HGNamedPipeServerImpl; + pipeServerImpl->m_hConnectEvent = hConnectEvent; + pipeServerImpl->m_hWriteEvent = hWriteEvent; + pipeServerImpl->m_hReadEvent = hReadEvent; + pipeServerImpl->m_hProcessEvent = hProcessEvent; + pipeServerImpl->m_hPipe = hPipe; + *server = (HGNamedPipeServer)pipeServerImpl; +#else + // TODO +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CloseNamedPipeServer(HGNamedPipeServer server) +{ + if (NULL == server) + { + return HGBASE_ERR_INVALIDARG; + } + + HGNamedPipeServerImpl* pipeServerImpl = (HGNamedPipeServerImpl*)server; + delete pipeServerImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_NamedPipeServerWrite(HGNamedPipeServer server, const HGByte* data, HGUInt size, HGUInt* writeSize) +{ + if (NULL == server || NULL == data || 0 == size) + { + return HGBASE_ERR_INVALIDARG; + } + + HGNamedPipeServerImpl* pipeServerImpl = (HGNamedPipeServerImpl*)server; +#if defined(HG_CMP_MSC) + if (NULL == pipeServerImpl->m_thread || pipeServerImpl->m_error || pipeServerImpl->m_break) + { + return HGBASE_ERR_FAIL; + } + + OVERLAPPED overlapped = { 0 }; + overlapped.hEvent = pipeServerImpl->m_hWriteEvent; + DWORD dwNumerOfWriteBytes = 0; + if (!WriteFile(pipeServerImpl->m_hPipe, data, size, &dwNumerOfWriteBytes, &overlapped)) + { + if (ERROR_IO_PENDING != GetLastError()) + { + // д + return HGBASE_ERR_FAIL; + } + + WaitForSingleObject(pipeServerImpl->m_hWriteEvent, INFINITE); + if (!GetOverlappedResult(pipeServerImpl->m_hPipe, &overlapped, &dwNumerOfWriteBytes, TRUE)) + { + // ֶֹͣ + return HGBASE_ERR_FAIL; + } + } + + if (NULL != writeSize) + *writeSize = dwNumerOfWriteBytes; +#else + // TODO +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_NamedPipeServerRead(HGNamedPipeServer server, HGByte* data, HGUInt size, HGUInt* readSize) +{ + if (NULL == server || NULL == data || 0 == size) + { + return HGBASE_ERR_INVALIDARG; + } + + HGNamedPipeServerImpl* pipeServerImpl = (HGNamedPipeServerImpl*)server; +#if defined(HG_CMP_MSC) + if (NULL == pipeServerImpl->m_thread) // δ + { + OVERLAPPED overlapped = { 0 }; + overlapped.hEvent = pipeServerImpl->m_hConnectEvent; + if (!ConnectNamedPipe(pipeServerImpl->m_hPipe, &overlapped)) + { + DWORD err = GetLastError(); + if (ERROR_IO_PENDING != err && ERROR_PIPE_CONNECTED != err) + { + // ȴӳ + return HGBASE_ERR_FAIL; + } + + if (ERROR_IO_PENDING == err) + { + // ȴ + WaitForSingleObject(pipeServerImpl->m_hConnectEvent, INFINITE); + DWORD dwTransferBytes = 0; // ֵ + if (!GetOverlappedResult(pipeServerImpl->m_hPipe, &overlapped, &dwTransferBytes, TRUE)) + { + // ֶֹͣ + return HGBASE_ERR_FAIL; + } + } + } + + // ȡԷID + memset(&overlapped, 0, sizeof(OVERLAPPED)); + overlapped.hEvent = pipeServerImpl->m_hReadEvent; + DWORD dwNumerOfReadBytes = 0; + DWORD clientPid = 0; + if (!ReadFile(pipeServerImpl->m_hPipe, &clientPid, sizeof(DWORD), &dwNumerOfReadBytes, &overlapped)) + { + if (ERROR_IO_PENDING != GetLastError()) + { + // ȡ + return HGBASE_ERR_FAIL; + } + + WaitForSingleObject(pipeServerImpl->m_hReadEvent, INFINITE); + if (!GetOverlappedResult(pipeServerImpl->m_hPipe, &overlapped, &dwNumerOfReadBytes, TRUE)) + { + // ֶֹͣ + return HGBASE_ERR_FAIL; + } + } + if (sizeof(DWORD) != dwNumerOfReadBytes || 0 == clientPid) + { + return HGBASE_ERR_FAIL; + } + + // ͼID + memset(&overlapped, 0, sizeof(OVERLAPPED)); + overlapped.hEvent = pipeServerImpl->m_hWriteEvent; + DWORD dwNumerOfWriteBytes = 0; + DWORD serverPid = GetCurrentProcessId(); + if (!WriteFile(pipeServerImpl->m_hPipe, &serverPid, sizeof(DWORD), &dwNumerOfWriteBytes, &overlapped)) + { + if (ERROR_IO_PENDING != GetLastError()) + { + // д + return HGBASE_ERR_FAIL; + } + + WaitForSingleObject(pipeServerImpl->m_hWriteEvent, INFINITE); + if (!GetOverlappedResult(pipeServerImpl->m_hPipe, &overlapped, &dwNumerOfWriteBytes, TRUE)) + { + // ֶֹͣ + return HGBASE_ERR_FAIL; + } + } + if (sizeof(DWORD) != dwNumerOfWriteBytes) + { + return HGBASE_ERR_FAIL; + } + + // ̵߳ȴԷID + pipeServerImpl->m_clientPid = clientPid; + HGBase_OpenThread(NamedPipeServerFunc, pipeServerImpl, &pipeServerImpl->m_thread); + assert(NULL != pipeServerImpl->m_thread); + } + + if (pipeServerImpl->m_error || pipeServerImpl->m_break) + { + return HGBASE_ERR_FAIL; + } + + OVERLAPPED overlapped = { 0 }; + overlapped.hEvent = pipeServerImpl->m_hReadEvent; + DWORD dwNumerOfReadBytes = 0; + if (!ReadFile(pipeServerImpl->m_hPipe, data, size, &dwNumerOfReadBytes, &overlapped)) + { + if (ERROR_IO_PENDING != GetLastError()) + { + // ȡ + return HGBASE_ERR_FAIL; + } + + WaitForSingleObject(pipeServerImpl->m_hReadEvent, INFINITE); + if (!GetOverlappedResult(pipeServerImpl->m_hPipe, &overlapped, &dwNumerOfReadBytes, TRUE)) + { + // ֶֹͣ + return HGBASE_ERR_FAIL; + } + } + + if (NULL != readSize) + *readSize = dwNumerOfReadBytes; +#else + // TODO +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_NamedPipeServerStop(HGNamedPipeServer server) +{ + if (NULL == server) + { + return HGBASE_ERR_INVALIDARG; + } + + HGNamedPipeServerImpl* pipeServerImpl = (HGNamedPipeServerImpl*)server; +#if defined(HG_CMP_MSC) + pipeServerImpl->m_break = HGTRUE; + SetEvent(pipeServerImpl->m_hConnectEvent); + SetEvent(pipeServerImpl->m_hWriteEvent); + SetEvent(pipeServerImpl->m_hReadEvent); + SetEvent(pipeServerImpl->m_hProcessEvent); +#else + // TODO +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_OpenNamedPipeClient(const HGChar* pipeName, HGNamedPipeClient* client) +{ + if (NULL == pipeName || NULL == client) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + HANDLE hWriteEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + assert(NULL != hWriteEvent); + HANDLE hReadEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + assert(NULL != hReadEvent); + HANDLE hProcessEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + assert(NULL != hProcessEvent); + + char name[256]; + sprintf(name, "\\\\.\\pipe\\%s", pipeName); + HANDLE hPipe = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (INVALID_HANDLE_VALUE == hPipe) + { + CloseHandle(hProcessEvent); + CloseHandle(hReadEvent); + CloseHandle(hWriteEvent); + return HGBASE_ERR_FAIL; + } + + // ͼID + OVERLAPPED overlapped = { 0 }; + overlapped.hEvent = hWriteEvent; + DWORD dwNumerOfWriteBytes = 0; + DWORD clientPid = GetCurrentProcessId(); + if (!WriteFile(hPipe, &clientPid, sizeof(DWORD), &dwNumerOfWriteBytes, &overlapped)) + { + if (ERROR_IO_PENDING != GetLastError()) + { + // д + CloseHandle(hPipe); + CloseHandle(hProcessEvent); + CloseHandle(hReadEvent); + CloseHandle(hWriteEvent); + return HGBASE_ERR_FAIL; + } + + WaitForSingleObject(hWriteEvent, INFINITE); + if (!GetOverlappedResult(hPipe, &overlapped, &dwNumerOfWriteBytes, TRUE)) + { + // ֶֹͣ + CloseHandle(hPipe); + CloseHandle(hProcessEvent); + CloseHandle(hReadEvent); + CloseHandle(hWriteEvent); + return HGBASE_ERR_FAIL; + } + } + if (sizeof(DWORD) != dwNumerOfWriteBytes) + { + CloseHandle(hPipe); + CloseHandle(hProcessEvent); + CloseHandle(hReadEvent); + CloseHandle(hWriteEvent); + return HGBASE_ERR_FAIL; + } + + // ȡԷID + memset(&overlapped, 0, sizeof(OVERLAPPED)); + overlapped.hEvent = hReadEvent; + DWORD dwNumerOfReadBytes = 0; + DWORD serverPid = 0; + if (!ReadFile(hPipe, &serverPid, sizeof(DWORD), &dwNumerOfReadBytes, &overlapped)) + { + if (ERROR_IO_PENDING != GetLastError()) + { + // ȡ + CloseHandle(hPipe); + CloseHandle(hProcessEvent); + CloseHandle(hReadEvent); + CloseHandle(hWriteEvent); + return HGBASE_ERR_FAIL; + } + + WaitForSingleObject(hReadEvent, INFINITE); + if (!GetOverlappedResult(hPipe, &overlapped, &dwNumerOfReadBytes, TRUE)) + { + // ֶֹͣ + CloseHandle(hPipe); + CloseHandle(hProcessEvent); + CloseHandle(hReadEvent); + CloseHandle(hWriteEvent); + return HGBASE_ERR_FAIL; + } + } + if (sizeof(DWORD) != dwNumerOfReadBytes || 0 == serverPid) + { + CloseHandle(hPipe); + CloseHandle(hProcessEvent); + CloseHandle(hReadEvent); + CloseHandle(hWriteEvent); + return HGBASE_ERR_FAIL; + } + + // ̵߳ȴԷID + + HGNamedPipeClientImpl* pipeClientImpl = new HGNamedPipeClientImpl; + pipeClientImpl->m_hWriteEvent = hWriteEvent; + pipeClientImpl->m_hReadEvent = hReadEvent; + pipeClientImpl->m_hProcessEvent = hProcessEvent; + pipeClientImpl->m_hPipe = hPipe; + pipeClientImpl->m_serverPid = serverPid; + HGBase_OpenThread(NamedPipeServerFunc, pipeClientImpl, &pipeClientImpl->m_thread); + assert(NULL != pipeClientImpl->m_thread); + *client = (HGNamedPipeClient)pipeClientImpl; +#else + // TODO +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CloseNamedPipeClient(HGNamedPipeClient client) +{ + if (NULL == client) + { + return HGBASE_ERR_INVALIDARG; + } + + HGNamedPipeClientImpl* pipeClientImpl = (HGNamedPipeClientImpl*)client; + delete pipeClientImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_NamedPipeClientWrite(HGNamedPipeClient client, const HGByte* data, HGUInt size, HGUInt* writeSize) +{ + if (NULL == client) + { + return HGBASE_ERR_INVALIDARG; + } + + HGNamedPipeClientImpl* pipeClientImpl = (HGNamedPipeClientImpl*)client; +#if defined(HG_CMP_MSC) + assert(NULL != pipeClientImpl->m_thread); + + if (pipeClientImpl->m_error || pipeClientImpl->m_break) + { + return HGBASE_ERR_FAIL; + } + + OVERLAPPED overlapped = { 0 }; + overlapped.hEvent = pipeClientImpl->m_hWriteEvent; + DWORD dwNumerOfWriteBytes = 0; + if (!WriteFile(pipeClientImpl->m_hPipe, data, size, &dwNumerOfWriteBytes, &overlapped)) + { + if (ERROR_IO_PENDING != GetLastError()) + { + // д + return HGBASE_ERR_FAIL; + } + + WaitForSingleObject(pipeClientImpl->m_hWriteEvent, INFINITE); + if (!GetOverlappedResult(pipeClientImpl->m_hPipe, &overlapped, &dwNumerOfWriteBytes, TRUE)) + { + // ֶֹͣ + return HGBASE_ERR_FAIL; + } + } + if (NULL != writeSize) + *writeSize = dwNumerOfWriteBytes; +#else + // TODO +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_NamedPipeClientRead(HGNamedPipeClient client, HGByte* data, HGUInt size, HGUInt* readSize) +{ + if (NULL == client) + { + return HGBASE_ERR_INVALIDARG; + } + + HGNamedPipeClientImpl* pipeClientImpl = (HGNamedPipeClientImpl*)client; +#if defined(HG_CMP_MSC) + assert(NULL != pipeClientImpl->m_thread); + + if (pipeClientImpl->m_error || pipeClientImpl->m_break) + { + return HGBASE_ERR_FAIL; + } + + OVERLAPPED overlapped = { 0 }; + overlapped.hEvent = pipeClientImpl->m_hReadEvent; + DWORD dwNumerOfReadBytes = 0; + if (!ReadFile(pipeClientImpl->m_hPipe, data, size, &dwNumerOfReadBytes, &overlapped)) + { + if (ERROR_IO_PENDING != GetLastError()) + { + // ȡ + return HGBASE_ERR_FAIL; + } + + WaitForSingleObject(pipeClientImpl->m_hReadEvent, INFINITE); + if (!GetOverlappedResult(pipeClientImpl->m_hPipe, &overlapped, &dwNumerOfReadBytes, TRUE)) + { + // ֶֹͣ + return HGBASE_ERR_FAIL; + } + } + + if (NULL != readSize) + *readSize = dwNumerOfReadBytes; +#else + // TODO +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_NamedPipeClientStop(HGNamedPipeClient client) +{ + if (NULL == client) + { + return HGBASE_ERR_INVALIDARG; + } + + HGNamedPipeClientImpl* pipeClientImpl = (HGNamedPipeClientImpl*)client; +#if defined(HG_CMP_MSC) + pipeClientImpl->m_break = HGTRUE; + SetEvent(pipeClientImpl->m_hWriteEvent); + SetEvent(pipeClientImpl->m_hReadEvent); + SetEvent(pipeClientImpl->m_hProcessEvent); +#else + // TODO +#endif + return HGBASE_ERR_OK; +} diff --git a/app/modules/base/HGNamedPipe.h b/app/modules/base/HGNamedPipe.h new file mode 100644 index 0000000..2467203 --- /dev/null +++ b/app/modules/base/HGNamedPipe.h @@ -0,0 +1,30 @@ +#ifndef __HGNAMEDPIPE_H__ +#define __HGNAMEDPIPE_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGNamedPipeServer); +HG_DECLARE_HANDLE(HGNamedPipeClient); + +HGEXPORT HGResult HGAPI HGBase_OpenNamedPipeServer(const HGChar* pipeName, HGNamedPipeServer *server); + +HGEXPORT HGResult HGAPI HGBase_CloseNamedPipeServer(HGNamedPipeServer server); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeServerWrite(HGNamedPipeServer server, const HGByte* data, HGUInt size, HGUInt* writeSize); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeServerRead(HGNamedPipeServer server, HGByte* data, HGUInt size, HGUInt* readSize); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeServerStop(HGNamedPipeServer server); + +HGEXPORT HGResult HGAPI HGBase_OpenNamedPipeClient(const HGChar* pipeName, HGNamedPipeClient* client); + +HGEXPORT HGResult HGAPI HGBase_CloseNamedPipeClient(HGNamedPipeClient client); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeClientWrite(HGNamedPipeClient client, const HGByte* data, HGUInt size, HGUInt* writeSize); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeClientRead(HGNamedPipeClient client, HGByte* data, HGUInt size, HGUInt* readSize); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeClientStop(HGNamedPipeClient client); + +#endif /* __HGNAMEDPIPE_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGThread.cpp b/app/modules/base/HGThread.cpp new file mode 100644 index 0000000..5eee219 --- /dev/null +++ b/app/modules/base/HGThread.cpp @@ -0,0 +1,102 @@ +#include "HGThread.h" +#include "HGInc.h" + +struct HGThreadImpl +{ + HGThreadImpl() + { +#if !defined(HG_CMP_MSC) + m_ntid = 0; +#else + m_thread = NULL; +#endif + m_func = NULL; + m_param = 0; + } + + ~HGThreadImpl() + { +#if !defined(HG_CMP_MSC) + if (0 != m_ntid) + { + pthread_join(m_ntid, NULL); + m_ntid = 0; + } +#else + if (NULL != m_thread) + { + WaitForSingleObject(m_thread, INFINITE); + CloseHandle(m_thread); + m_thread = NULL; + } +#endif + m_param = 0; + m_func = NULL; + } + +#if !defined(HG_CMP_MSC) + static void* thread_fun(void* arg) + { + HGThreadImpl* p = (HGThreadImpl*)arg; + p->m_func((HGThread)p, p->m_param); + return NULL; + } +#else + static DWORD WINAPI ThreadCallback(LPVOID param) + { + HGThreadImpl* p = (HGThreadImpl*)param; + p->m_func((HGThread)p, p->m_param); + return 0; + } +#endif + +#if !defined(HG_CMP_MSC) + pthread_t m_ntid; +#else + HANDLE m_thread; +#endif + HGThreadFunc m_func; + HGPointer m_param; +}; + +HGResult HGAPI HGBase_OpenThread(HGThreadFunc func, HGPointer param, HGThread* thread) +{ + if (NULL == func || NULL == thread) + { + return HGBASE_ERR_INVALIDARG; + } + + HGThreadImpl* threadImpl = new HGThreadImpl; + threadImpl->m_func = func; + threadImpl->m_param = param; + +#if !defined(HG_CMP_MSC) + if (0 != pthread_create(&threadImpl->m_ntid, NULL, HGThreadImpl::thread_fun, threadImpl)) + { + delete threadImpl; + return HGBASE_ERR_FAIL; + } +#else + threadImpl->m_thread = CreateThread(NULL, 0, HGThreadImpl::ThreadCallback, threadImpl, 0, NULL); + if (NULL == threadImpl->m_thread) + { + delete threadImpl; + return HGBASE_ERR_FAIL; + } +#endif + + * thread = (HGThread)threadImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CloseThread(HGThread thread) +{ + if (NULL == thread) + { + return HGBASE_ERR_INVALIDARG; + } + + HGThreadImpl* threadImpl = (HGThreadImpl*)thread; + delete threadImpl; + return HGBASE_ERR_OK; +} diff --git a/app/modules/base/HGThread.h b/app/modules/base/HGThread.h new file mode 100644 index 0000000..4c688fc --- /dev/null +++ b/app/modules/base/HGThread.h @@ -0,0 +1,34 @@ +#ifndef __HGTHREAD_H__ +#define __HGTHREAD_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGThread); + +/* 线程回调函数 +* 参数: +* 1) thread: in, 线程句柄 +* 2) param: in, 回调参数 +* 说明: +*/ +typedef void (HGAPI *HGThreadFunc)(HGThread thread, HGPointer param); + +/* 开启线程 +* 参数: +* 1) func: in, 线程回调函数 +* 2) param: in, 回调参数 +* 3) thread: out, 线程句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_OpenThread(HGThreadFunc func, HGPointer param, HGThread *thread); + +/* 关闭线程 +* 参数: +* 1) thread: in, 线程句柄 +* 说明: +* 1) 该函数会等待线程正常结束, 如果线程阻塞, 该函数也会阻塞 +*/ +HGEXPORT HGResult HGAPI HGBase_CloseThread(HGThread thread); + +#endif /* __HGTHREAD_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGTime.cpp b/app/modules/base/HGTime.cpp new file mode 100644 index 0000000..aded4bf --- /dev/null +++ b/app/modules/base/HGTime.cpp @@ -0,0 +1,37 @@ +#include "HGTime.h" +#include "HGInc.h" + +HGResult HGAPI HGBase_GetLocalTime(HGTimeInfo* timeInfo) +{ + if (NULL == timeInfo) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + SYSTEMTIME st; + GetLocalTime(&st); + timeInfo->year = st.wYear; + timeInfo->month = st.wMonth; + timeInfo->day = st.wDay; + timeInfo->dayOfWeek = st.wDayOfWeek; + timeInfo->hour = st.wHour; + timeInfo->minute = st.wMinute; + timeInfo->second = st.wSecond; + timeInfo->milliseconds = st.wMilliseconds; +#else + struct timeval time; + gettimeofday(&time, NULL); + struct tm* p = localtime(&time.tv_sec); + assert(NULL != p); + timeInfo->year = p->tm_year + 1900; + timeInfo->month = 1 + p->tm_mon; + timeInfo->day = p->tm_mday; + timeInfo->dayOfWeek = p->tm_wday; + timeInfo->hour = p->tm_hour; + timeInfo->minute = p->tm_min; + timeInfo->second = p->tm_sec; + timeInfo->milliseconds = time.tv_usec / 1000; +#endif + return HGBASE_ERR_OK; +} \ No newline at end of file diff --git a/app/modules/base/HGTime.h b/app/modules/base/HGTime.h new file mode 100644 index 0000000..41fb8e4 --- /dev/null +++ b/app/modules/base/HGTime.h @@ -0,0 +1,26 @@ +#ifndef __HGTIME_H__ +#define __HGTIME_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUShort year; + HGUShort month; + HGUShort day; + HGUShort dayOfWeek; /* 0Ϊ, 1-6ʾһ */ + HGUShort hour; + HGUShort minute; + HGUShort second; + HGUShort milliseconds; +}HGTimeInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGBase_GetLocalTime(HGTimeInfo *timeInfo); + +#endif /* __HGTIME_H__ */ \ No newline at end of file diff --git a/app/modules/base/HGUtility.cpp b/app/modules/base/HGUtility.cpp new file mode 100644 index 0000000..4c30fdb --- /dev/null +++ b/app/modules/base/HGUtility.cpp @@ -0,0 +1,650 @@ +#include "HGUtility.h" +#include "HGInc.h" +#include "HGInfo.h" +#include "HGIni.h" +#if defined(HG_CMP_MSC) +#include +#include +#else +#include "uuid/uuid.h" +#endif +#include + +HGResult HGAPI HGBase_GetTmpPath(HGChar* path, HGUInt maxLen) +{ + if (NULL == path || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + char tmpPath[512] = {0}; + strcpy(tmpPath, "/tmp/"); +#else + CHAR tmpPath[MAX_PATH] = { 0 }; + DWORD len = GetTempPathA(MAX_PATH, tmpPath); + if (0 == len) + return HGBASE_ERR_FAIL; + if (tmpPath[strlen(tmpPath) - 1] != '\\') + strcat(tmpPath, "\\"); +#endif + + if (maxLen < strlen(tmpPath) + 1) + return HGBASE_ERR_FAIL; + strcpy(path, tmpPath); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetCurrentDir(HGChar* dir, HGUInt maxLen) +{ + if (NULL == dir || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + char buffer[512] = { 0 }; + char* p = getcwd(buffer, 512); + if (NULL == p) + return HGBASE_ERR_FAIL; + if (buffer[strlen(buffer) - 1] != '/') + strcat(buffer, "/"); +#else + CHAR buffer[MAX_PATH] = { 0 }; + DWORD len = GetCurrentDirectoryA(MAX_PATH, buffer); + if (0 == len) + return HGBASE_ERR_FAIL; + if (buffer[strlen(buffer) - 1] != '\\') + strcat(buffer, "\\"); +#endif + + if (maxLen < strlen(buffer) + 1) + return HGBASE_ERR_FAIL; + strcpy(dir, buffer); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_SetCurrentDir(const HGChar* dir) +{ + if (NULL == dir) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + if (0 != chdir(dir)) + return HGBASE_ERR_FAIL; +#else + if (!SetCurrentDirectoryA(dir)) + return HGBASE_ERR_FAIL; +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_CreateDir(const HGChar* dir) +{ + if (NULL == dir) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + bool ret = true; + + char muldir[512] = { 0 }; + strcpy(muldir, dir); + for (size_t i = 0; i < strlen(muldir); ++i) + { + if ('/' == muldir[i]) + { + muldir[i] = '\0'; + if ('\0' != *muldir && 0 != access(muldir, 0)) + { + if (0 != mkdir(muldir, 0777)) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGBase_CreateDir: mkdir fail, %s errno=%d", dir, errno); + ret = false; + break; + } + } + muldir[i] = '/'; + } + } + + if (ret) + { + if ('\0' != *muldir && 0 != access(muldir, 0)) + { + if (0 != mkdir(muldir, 0777)) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGBase_CreateDir: mkdir fail, %s errno=%d", dir, errno); + ret = false; + } + } + } + + if (!ret) + return HGBASE_ERR_ACCESSDENIED; +#else + int ret = SHCreateDirectoryExA(NULL, dir, NULL); + if (ERROR_SUCCESS != ret && ERROR_ALREADY_EXISTS != ret) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGBase_CreateDir: SHCreateDirectoryExA fail, %s GetLastError=%u", dir, GetLastError()); + return HGBASE_ERR_ACCESSDENIED; + } +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_DeleteDir(const HGChar* dir) +{ + if (NULL == dir) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + if (0 != rmdir(dir)) + return HGBASE_ERR_FAIL; +#else + if (!RemoveDirectoryA(dir)) + return HGBASE_ERR_FAIL; +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_DeleteFile(const HGChar* fileName) +{ + if (NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + if (0 != unlink(fileName)) + return HGBASE_ERR_FAIL; +#else + if (!DeleteFileA(fileName)) + return HGBASE_ERR_FAIL; +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetModuleName(HGPointer addr, HGChar* name, HGUInt maxLen) +{ + if (NULL == name || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + if (NULL == addr) + { + char dir[PATH_MAX] = {0}; + if (0 == readlink("/proc/self/exe", dir, PATH_MAX)) + return HGBASE_ERR_FAIL; + if (maxLen < strlen(dir) + 1) + return HGBASE_ERR_FAIL; + strcpy(name, dir); + } + else + { + Dl_info dlinfo; + if (0 == dladdr(addr, &dlinfo)) + return HGBASE_ERR_FAIL; + if (maxLen < strlen(dlinfo.dli_fname) + 1) + return HGBASE_ERR_FAIL; + strcpy(name, dlinfo.dli_fname); + } +#else + HMODULE hModule = NULL; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR)addr, &hModule); + + CHAR moduleName[MAX_PATH] = { 0 }; + DWORD len = GetModuleFileNameA(hModule, moduleName, MAX_PATH); + if (0 == len || maxLen < strlen(moduleName) + 1) + return HGBASE_ERR_FAIL; + strcpy(name, moduleName); +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetUuid(HGChar* uuid, HGUInt maxLen) +{ + if (NULL == uuid || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + +#if !defined(HG_CMP_MSC) + uuid_t id; + uuid_generate(id); + + char str[128] = {0}; + uuid_unparse(id, str); + if (maxLen < strlen(str) + 1) + return HGBASE_ERR_FAIL; + strcpy(uuid, str); +#else + GUID guid; + if (S_OK != CoCreateGuid(&guid)) + return HGBASE_ERR_FAIL; + + char str[128] = {0}; + sprintf(str, "%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], + guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); + if (maxLen < strlen(str) + 1) + return HGBASE_ERR_FAIL; + strcpy(uuid, str); +#endif + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetTmpFileName(const HGChar* suffix, HGChar* fileName, HGUInt maxLen) +{ + if (NULL == fileName || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + + HGChar path[256] = { 0 }, uuid[128] = {0}; + HGBase_GetTmpPath(path, 256); + HGBase_GetUuid(uuid, 128); + strcat(path, uuid); + if (NULL != suffix && 0 != *suffix) + { + strcat(path, "."); + strcat(path, suffix); + } + + if (maxLen < strlen(path) + 1) + return HGBASE_ERR_FAIL; + strcpy(fileName, path); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetConfigPath(HGChar* configPath, HGUInt maxLen) +{ + if (NULL == configPath || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + + HGChar moduleName[256]; + HGBase_GetModuleName(NULL, moduleName, 256); + HGChar modulePath[256]; + HGBase_GetFilePath(moduleName, modulePath, 256); + strcat(modulePath, "first.cfg"); + + HGChar dataPath[256] = {0}; + HGBase_GetProfileString(modulePath, "constraints", "local_data_path", "", dataPath, 256); + if ('\0' != *dataPath) + { +#if defined(HG_CMP_MSC) + if (dataPath[strlen(dataPath) - 1] != '\\') + strcat(dataPath, "\\"); + strcat(dataPath, "Cfg\\"); +#else + if (dataPath[strlen(dataPath) - 1] != '/') + strcat(dataPath, "/"); + strcat(dataPath, "Cfg/"); +#endif + + if (maxLen < strlen(dataPath) + 1) + return HGBASE_ERR_FAIL; + strcpy(configPath, dataPath); + return HGBASE_ERR_OK; + } + +#if defined(HG_CMP_MSC) + CHAR cfgPath[MAX_PATH] = { 0 }; + BOOL ret = SHGetSpecialFolderPathA(NULL, cfgPath, CSIDL_APPDATA, FALSE); + if (!ret) + return HGBASE_ERR_FAIL; + if (cfgPath[strlen(cfgPath) - 1] != '\\') + strcat(cfgPath, "\\"); + + HGChar procName[64]; + HGBase_GetProcessName(procName, 64); + strcat(cfgPath, procName); + strcat(cfgPath, "\\Cfg\\"); +#else + char cfgPath[512] = { 0 }; + strcpy(cfgPath, getenv("HOME")); + if (cfgPath[strlen(cfgPath) - 1] != '/') + strcat(cfgPath, "/"); + + strcat(cfgPath, "."); + HGChar procName[64]; + HGBase_GetProcessName(procName, 64); + strcat(cfgPath, procName); + strcat(cfgPath, "/Cfg/"); +#endif + + if (maxLen < strlen(cfgPath) + 1) + return HGBASE_ERR_FAIL; + strcpy(configPath, cfgPath); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetLogFilePath(HGChar* logFilePath, HGUInt maxLen) +{ + if (NULL == logFilePath || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + + HGChar moduleName[256]; + HGBase_GetModuleName(NULL, moduleName, 256); + HGChar modulePath[256]; + HGBase_GetFilePath(moduleName, modulePath, 256); + strcat(modulePath, "first.cfg"); + + HGChar dataPath[256] = { 0 }; + HGBase_GetProfileString(modulePath, "constraints", "local_data_path", "", dataPath, 256); + if ('\0' != *dataPath) + { +#if defined(HG_CMP_MSC) + if (dataPath[strlen(dataPath) - 1] != '\\') + strcat(dataPath, "\\"); + strcat(dataPath, "Cfg\\"); +#else + if (dataPath[strlen(dataPath) - 1] != '/') + strcat(dataPath, "/"); + strcat(dataPath, "Cfg/"); +#endif + + if (maxLen < strlen(dataPath) + 1) + return HGBASE_ERR_FAIL; + strcpy(logFilePath, dataPath); + return HGBASE_ERR_OK; + } + +#if defined(HG_CMP_MSC) + CHAR logPath[MAX_PATH] = { 0 }; + BOOL ret = SHGetSpecialFolderPathA(NULL, logPath, CSIDL_APPDATA, FALSE); + if (!ret) + return HGBASE_ERR_FAIL; + if (logPath[strlen(logPath) - 1] != '\\') + strcat(logPath, "\\"); + + HGChar procName[64]; + HGBase_GetProcessName(procName, 64); + strcat(logPath, procName); + strcat(logPath, "\\Log\\"); +#else + char logPath[512] = { 0 }; + strcpy(logPath, getenv("HOME")); + if (logPath[strlen(logPath) - 1] != '/') + strcat(logPath, "/"); + + strcat(logPath, "."); + HGChar procName[64]; + HGBase_GetProcessName(procName, 64); + strcat(logPath, procName); + strcat(logPath, "/Log/"); +#endif + + if (maxLen < strlen(logPath) + 1) + return HGBASE_ERR_FAIL; + strcpy(logFilePath, logPath); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetDocumentsPath(HGChar* documentsPath, HGUInt maxLen) +{ + if (NULL == documentsPath || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + CHAR docPath[MAX_PATH] = { 0 }; + BOOL ret = SHGetSpecialFolderPathA(NULL, docPath, CSIDL_MYDOCUMENTS, FALSE); + if (!ret) + return HGBASE_ERR_FAIL; + if (docPath[strlen(docPath) - 1] != '\\') + strcat(docPath, "\\"); +#else + char docPath[512] = { 0 }; + strcpy(docPath, getenv("HOME")); + if (docPath[strlen(docPath) - 1] != '/') + strcat(docPath, "/"); + strcat(docPath, "Documents/"); +#endif + + if (maxLen < strlen(docPath) + 1) + return HGBASE_ERR_FAIL; + strcpy(documentsPath, docPath); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetProcessName(HGChar* name, HGUInt maxLen) +{ + if (NULL == name || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + CHAR moduleName[MAX_PATH] = { 0 }; + DWORD len = GetModuleFileNameA(NULL, moduleName, MAX_PATH); + if (0 == len) + return HGBASE_ERR_FAIL; + CStringA strModuleName(moduleName); + int pos = strModuleName.ReverseFind('\\'); + if (-1 == pos) + return HGBASE_ERR_FAIL; + strModuleName = strModuleName.Right(strModuleName.GetLength() - pos - 1); + pos = strModuleName.ReverseFind('.'); + if (-1 != pos) + strModuleName = strModuleName.Left(pos); + if (maxLen < (HGUInt)strModuleName.GetLength() + 1) + return HGBASE_ERR_FAIL; + strcpy(name, strModuleName); +#else + char aucPathBuf[1024] = { 0 }; + if (readlink("/proc/self/exe", aucPathBuf, 1024) <= 0) + return HGBASE_ERR_FAIL; + const char* pcName = strrchr(aucPathBuf, '/'); + if (NULL == pcName) + return HGBASE_ERR_FAIL; + ++pcName; + std::string procName(pcName); + const char* pcSuffix = strrchr(procName.c_str(), '.'); + if (NULL != pcSuffix) + procName = procName.substr(0, pcSuffix - procName.c_str()); + if (maxLen < (HGUInt)procName.size() + 1) + return HGBASE_ERR_FAIL; + strcpy(name, procName.c_str()); +#endif + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetFilePath(const HGChar* fileName, HGChar* path, HGUInt maxLen) +{ + if (NULL == fileName || NULL == path || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + const char* pcName = strrchr(fileName, '\\'); + if (NULL == pcName) + { + pcName = strrchr(fileName, '/'); + if (NULL == pcName) + return HGBASE_ERR_FAIL; + } +#else + const char* pcName = strrchr(fileName, '/'); + if (NULL == pcName) + return HGBASE_ERR_FAIL; +#endif + + ++pcName; + if (maxLen < (HGUInt)(pcName - fileName + 1)) + return HGBASE_ERR_FAIL; + memcpy(path, fileName, pcName - fileName); + path[pcName - fileName] = 0; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetFileName(const HGChar* fileName, HGChar* name, HGUInt maxLen) +{ + if (NULL == fileName || NULL == name || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + const char* pcName = strrchr(fileName, '\\'); + if (NULL == pcName) + { + pcName = strrchr(fileName, '/'); + if (NULL == pcName) + return HGBASE_ERR_FAIL; + } +#else + const char* pcName = strrchr(fileName, '/'); + if (NULL == pcName) + return HGBASE_ERR_FAIL; +#endif + + ++pcName; + if (maxLen < strlen(pcName) + 1) + return HGBASE_ERR_FAIL; + strcpy(name, pcName); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetFilePrefix(const HGChar* fileName, HGChar* prefix, HGUInt maxLen) +{ + if (NULL == fileName || NULL == prefix || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + CStringA strPrefix; + CStringA strFileName(fileName); + int pos = strFileName.ReverseFind('.'); + if (-1 == pos) + strPrefix = strFileName; + else + { + CStringA strSuffix = strFileName.Right(strFileName.GetLength() - pos - 1); + if (-1 != strSuffix.Find('\\') || -1 != strSuffix.Find('/')) + strPrefix = strFileName; + else + strPrefix = strFileName.Left(pos); + } + if (maxLen < (HGUInt)strPrefix.GetLength() + 1) + return HGBASE_ERR_FAIL; + strcpy(prefix, strPrefix); +#else + std::string strPrefix; + const char* pcSuffix = strrchr(fileName, '.'); + if (NULL == pcSuffix) + strPrefix = fileName; + else + { + if (NULL != strchr(pcSuffix + 1, '/')) + strPrefix = fileName; + else + strPrefix = std::string(fileName, pcSuffix - fileName); + } + if (maxLen < (HGUInt)strPrefix.size() + 1) + return HGBASE_ERR_FAIL; + strcpy(prefix, strPrefix.c_str()); +#endif + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_GetFileSuffix(const HGChar* fileName, HGChar* suffix, HGUInt maxLen) +{ + if (NULL == fileName || NULL == suffix || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + CStringA strFileName(fileName); + int pos = strFileName.ReverseFind('.'); + if (-1 == pos) + return HGBASE_ERR_FAIL; + CStringA strSuffix = strFileName.Right(strFileName.GetLength() - pos - 1); + if (-1 != strSuffix.Find('\\') || -1 != strSuffix.Find('/')) + return HGBASE_ERR_FAIL; + if (maxLen < (HGUInt)strSuffix.GetLength() + 1) + return HGBASE_ERR_FAIL; + strcpy(suffix, strSuffix); +#else + const char* pcSuffix = strrchr(fileName, '.'); + if (NULL == pcSuffix) + return HGBASE_ERR_FAIL; + ++pcSuffix; + if (NULL != strchr(pcSuffix, '/')) + return HGBASE_ERR_FAIL; + if (maxLen < (HGUInt)strlen(pcSuffix) + 1) + return HGBASE_ERR_FAIL; + strcpy(suffix, pcSuffix); +#endif + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGBase_StandardiseFileName(const HGChar* fileName, HGChar* result, HGUInt maxLen) +{ + if (NULL == fileName || NULL == result || 0 == maxLen) + { + return HGBASE_ERR_INVALIDARG; + } + + std::string stdFileName; +#if defined(HG_CMP_MSC) + bool separator = false; + for (const HGChar* p = fileName; *p != 0; ++p) + { + if (*p == '\\' || *p == '/') + { + if (!separator) + { + stdFileName.push_back('\\'); + separator = true; + } + } + else + { + stdFileName.push_back(*p); + separator = false; + } + } +#else + bool separator = false; + for (const HGChar* p = fileName; *p != 0; ++p) + { + if (*p == '/') + { + if (!separator) + { + stdFileName.push_back('/'); + separator = true; + } +} + else + { + stdFileName.push_back(*p); + separator = false; + } + } +#endif + + if (maxLen < (HGUInt)stdFileName.size() + 1) + return HGBASE_ERR_FAIL; + strcpy(result, stdFileName.c_str()); + return HGBASE_ERR_OK; +} diff --git a/app/modules/base/HGUtility.h b/app/modules/base/HGUtility.h new file mode 100644 index 0000000..aa388e3 --- /dev/null +++ b/app/modules/base/HGUtility.h @@ -0,0 +1,80 @@ +#ifndef __HGUTILITY_H__ +#define __HGUTILITY_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* 获取系统临时文件目录 +*/ +HGEXPORT HGResult HGAPI HGBase_GetTmpPath(HGChar* path, HGUInt maxLen); + +/* 获取进程的当前工作目录 +*/ +HGEXPORT HGResult HGAPI HGBase_GetCurrentDir(HGChar* dir, HGUInt maxLen); + +/* 设置进程的当前工作目录 +*/ +HGEXPORT HGResult HGAPI HGBase_SetCurrentDir(const HGChar* dir); + +/* 创建目录 +* 该函数可以创建多级目录 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateDir(const HGChar* dir); + +/* 删除目录 +* 该函数只能用于删除空目录 +*/ +HGEXPORT HGResult HGAPI HGBase_DeleteDir(const HGChar* dir); + +/* 删除文件 +*/ +HGEXPORT HGResult HGAPI HGBase_DeleteFile(const HGChar* fileName); + +/* 获取模块名称 +*/ +HGEXPORT HGResult HGAPI HGBase_GetModuleName(HGPointer addr, HGChar* name, HGUInt maxLen); + +/* 获取UUID +*/ +HGEXPORT HGResult HGAPI HGBase_GetUuid(HGChar* uuid, HGUInt maxLen); + +/* 获取临时文件名 +*/ +HGEXPORT HGResult HGAPI HGBase_GetTmpFileName(const HGChar *suffix, HGChar* fileName, HGUInt maxLen); + +/* 获取配置文件路径 +*/ +HGEXPORT HGResult HGAPI HGBase_GetConfigPath(HGChar* configPath, HGUInt maxLen); + +/* 获取日志文件路径 +*/ +HGEXPORT HGResult HGAPI HGBase_GetLogFilePath(HGChar* logFilePath, HGUInt maxLen); + +/* 获取文档路径 +*/ +HGEXPORT HGResult HGAPI HGBase_GetDocumentsPath(HGChar* documentsPath, HGUInt maxLen); + +/* 获取进程名 +*/ +HGEXPORT HGResult HGAPI HGBase_GetProcessName(HGChar* name, HGUInt maxLen); + +/* 通过文件全路径获取路径 +*/ +HGEXPORT HGResult HGAPI HGBase_GetFilePath(const HGChar* fileName, HGChar* path, HGUInt maxLen); + +/* 通过文件全路径获取文件名 +*/ +HGEXPORT HGResult HGAPI HGBase_GetFileName(const HGChar* fileName, HGChar* name, HGUInt maxLen); + +/* 通过文件名获取文件前缀 +*/ +HGEXPORT HGResult HGAPI HGBase_GetFilePrefix(const HGChar* fileName, HGChar* prefix, HGUInt maxLen); + +/* 通过文件名获取文件后缀 +*/ +HGEXPORT HGResult HGAPI HGBase_GetFileSuffix(const HGChar *fileName, HGChar* suffix, HGUInt maxLen); + +/* 将文件名标准化 */ +HGEXPORT HGResult HGAPI HGBase_StandardiseFileName(const HGChar* fileName, HGChar *result, HGUInt maxLen); + +#endif /* __HGUTILITY_H__ */ \ No newline at end of file diff --git a/app/modules/base/dllmain.cpp b/app/modules/base/dllmain.cpp new file mode 100644 index 0000000..22b0c5d --- /dev/null +++ b/app/modules/base/dllmain.cpp @@ -0,0 +1,49 @@ +#include "HGDef.h" +#include "HGInfoImpl.hpp" +#include "HGInc.h" + +extern HGInfoImpl* g_infoImpl; + +#if defined(HG_CMP_MSC) + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + { + g_infoImpl = new HGInfoImpl; + } + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + { + delete g_infoImpl; + g_infoImpl = NULL; + } + break; + } + + return TRUE; +} + +#else + +void __attribute__((constructor)) global_load(void); +void __attribute__((destructor)) global_unload(void); + +void global_load(void) +{ + g_infoImpl = new HGInfoImpl; +} + +void global_unload(void) +{ + delete g_infoImpl; + g_infoImpl = NULL; +} + +#endif diff --git a/app/modules/imgfmt/HGBmp.cpp b/app/modules/imgfmt/HGBmp.cpp new file mode 100644 index 0000000..517d762 --- /dev/null +++ b/app/modules/imgfmt/HGBmp.cpp @@ -0,0 +1,557 @@ +#include "HGBmp.h" +#include "../base/HGInc.h" +#include "../base/HGInfo.h" +extern "C" +{ +#include "libnsbmp.h" +}; + +HGResult HGAPI HGImgFmt_CheckBmpFile(const HGChar* fileName, HGBool* isBmp) +{ + if (NULL == fileName || NULL == isBmp) + { + return HGBASE_ERR_INVALIDARG; + } + + HGBmpLoadInfo info; + HGResult ret = HGImgFmt_LoadBmpImage(fileName, &info, 0, 0, NULL); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + *isBmp = HGTRUE; + return ret; +} + +static void* bitmap_create(int width, int height, unsigned int state) +{ + if (width <= 0 || height <= 0) + { + return NULL; + } + + (void)state; /* unused */ + return calloc((intptr_t)width * (intptr_t)height, 4); +} + +static unsigned char* bitmap_get_buffer(void* bitmap) +{ + assert(NULL != bitmap); + return (unsigned char*)bitmap; +} + +static size_t bitmap_get_bpp(void* bitmap) +{ + (void)bitmap; /* unused */ + return 4; +} + +static void bitmap_destroy(void* bitmap) +{ + assert(NULL != bitmap); + free(bitmap); +} + +HGResult HGAPI HGImgFmt_LoadBmpImage(const HGChar* fileName, HGBmpLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL == image) + { + if (0 != imgType || 0 != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + else + { + if (0 != imgType && HGBASE_IMGTYPE_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType + && HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType + && HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + +#if defined(HG_CMP_MSC) + if (0 != _access(fileName, 0)) +#else + if (0 != access(fileName, 0)) +#endif + { + return HGBASE_ERR_FILENOTEXIST; + } + + FILE* file = fopen(fileName, "rb"); + if (NULL == file) + { + return HGBASE_ERR_ACCESSDENIED; + } + +#if defined(HG_CMP_MSC) + _fseeki64(file, 0, SEEK_END); + uint64_t size = _ftelli64(file); +#else + fseeko64(file, 0, SEEK_END); + uint64_t size = ftello64(file); +#endif + if (0 == size) + { + fclose(file); + file = NULL; + return HGBASE_ERR_FILEERROR; + } + + uint8_t* buffer = (uint8_t*)malloc((size_t)size); + if (NULL == buffer) + { + fclose(file); + file = NULL; + return HGBASE_ERR_OUTOFMEMORY; + } + +#if defined(HG_CMP_MSC) + _fseeki64(file, 0, SEEK_SET); +#else + fseeko64(file, 0, SEEK_SET); +#endif + size_t readSize = fread(buffer, 1, (size_t)size, file); + if (readSize != size) + { + free(buffer); + buffer = NULL; + fclose(file); + file = NULL; + return HGBASE_ERR_FAIL; + } + + bmp_image bmp; + bmp_bitmap_callback_vt bitmap_callbacks = { bitmap_create, bitmap_destroy, bitmap_get_buffer, bitmap_get_bpp }; + bmp_create(&bmp, &bitmap_callbacks); + + if (BMP_OK != bmp_analyse(&bmp, (size_t)size, buffer)) + { + bmp_finalise(&bmp); + free(buffer); + buffer = NULL; + fclose(file); + file = NULL; + return HGIMGFMT_ERR_FAIL; + } + + if (NULL != info) + { + info->width = bmp.width; + info->height = bmp.height; + info->bitCount = bmp.bpp; + info->compression = (uint32_t)bmp.encoding; + info->xPelsPerMeter = bmp.x_pels_per_meter; + info->yPelsPerMeter = bmp.y_pels_per_meter; + } + + if (NULL != image) + { + if (BMP_OK != bmp_decode(&bmp)) + { + bmp_finalise(&bmp); + free(buffer); + buffer = NULL; + fclose(file); + file = NULL; + return HGIMGFMT_ERR_FAIL; + } + + if (0 == imgType) + { + imgType = HGBASE_IMGTYPE_RGB; + + if (1 == bmp.bpp || 4 == bmp.bpp || 8 == bmp.bpp) + { + bool bGray = true; + bool bBinary = true; + for (uint32_t i = 0; i < bmp.colours; ++i) + { + HGByte red = (bmp.colour_table[i] >> 16) & 0xff; + HGByte green = (bmp.colour_table[i] >> 8) & 0xff; + HGByte blue = (bmp.colour_table[i]) & 0xff; + + if (red != green || red != blue || green != blue) + { + bGray = false; + bBinary = false; + break; + } + + if (red != 0 && red != 255) + { + bBinary = false; + } + } + + if (bBinary) + imgType = HGBASE_IMGTYPE_BINARY; + else if (bGray) + imgType = HGBASE_IMGTYPE_GRAY; + } + else if (32 == bmp.bpp) + { + imgType = HGBASE_IMGTYPE_RGBA; + } + } + + if (imgOrigin == 0) + { + imgOrigin = HGBASE_IMGORIGIN_TOP; + } + + HGImageInfo bmpImageInfo; + bmpImageInfo.width = bmp.width; + bmpImageInfo.height = bmp.height; + bmpImageInfo.type = HGBASE_IMGTYPE_RGBA; + bmpImageInfo.widthStep = bmp.width * 4; + bmpImageInfo.origin = HGBASE_IMGORIGIN_TOP; + + HGImage image2 = NULL; + HGResult ret = HGBase_CreateImageWithData((HGByte*)bmp.bitmap, &bmpImageInfo, &image2); + if (HGBASE_ERR_OK != ret) + { + bmp_finalise(&bmp); + free(buffer); + buffer = NULL; + fclose(file); + file = NULL; + return ret; + } + + uint32_t xDpi = (uint32_t)((double)bmp.x_pels_per_meter / 39.3700787 + 0.5); + uint32_t yDpi = (uint32_t)((double)bmp.y_pels_per_meter / 39.3700787 + 0.5); + HGBase_SetImageDpi(image2, xDpi, yDpi); + + ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); + HGBase_DestroyImage(image2); + if (HGBASE_ERR_OK != ret) + { + bmp_finalise(&bmp); + free(buffer); + buffer = NULL; + fclose(file); + file = NULL; + return ret; + } + } + + bmp_finalise(&bmp); + free(buffer); + buffer = NULL; + fclose(file); + file = NULL; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveBmpImage(HGImage image, const HGBmpSaveInfo* info, const HGChar* fileName) +{ + if (NULL == image || NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL != info) + { + // 检查合法性 + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + uint32_t width = imgInfo.width; + uint32_t height = imgInfo.height; + uint32_t widthStep = imgInfo.widthStep; + uint32_t type = imgInfo.type; + uint32_t origin = imgInfo.origin; + + HGUInt bpp = 0; + if (HGBASE_IMGTYPE_BINARY == type) + bpp = 1; + else if (HGBASE_IMGTYPE_GRAY == type) + bpp = 8; + else if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + bpp = 24; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + bpp = 32; + assert(0 != bpp); + HGUInt stdWidthStep = ((width * bpp + 31) & ~31) >> 3; + + if (widthStep != stdWidthStep) + { + HGImage imgTemp = NULL; + + HGImageRoi imageRoi; + HGBase_GetImageROI(image, &imageRoi); + HGBase_ResetImageROI(image); + HGResult ret = HGBase_CloneImage(image, 0, 0, &imgTemp); + HGBase_SetImageROI(image, &imageRoi); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGImgFmt_SaveBmpImage(imgTemp, info, fileName); + HGBase_DestroyImage(imgTemp); + return ret; + } + + FILE* file = fopen(fileName, "wb"); + if (NULL == file) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGImgFmt_SaveBmpImage: fopen fail, %s errno=%d", fileName, errno); + return HGBASE_ERR_ACCESSDENIED; + } + + uint8_t* buffer = (uint8_t*)malloc(widthStep * height); + if (NULL == buffer) + { + fclose(file); + file = NULL; + return HGBASE_ERR_OUTOFMEMORY; + } + + uint8_t fh[14]; + *(uint16_t*)fh = 0x4D42; + *(uint16_t*)(fh + 6) = 0; + *(uint16_t*)(fh + 8) = 0; + + uint8_t ih[40]; + *(uint32_t*)ih = 40; + *(int32_t*)(ih + 4) = (int32_t)width; + *(int32_t*)(ih + 8) = (int32_t)height; + *(uint16_t*)(ih + 12) = 1; + *(uint32_t*)(ih + 16) = 0; + *(uint32_t*)(ih + 20) = (widthStep * height); + *(int32_t*)(ih + 24) = 0; + *(int32_t*)(ih + 28) = 0; + *(uint32_t*)(ih + 32) = 0; + *(uint32_t*)(ih + 36) = 0; + + if (NULL != info) + { + *(int32_t*)(ih + 24) = (int32_t)info->xPelsPerMeter; + *(int32_t*)(ih + 28) = (int32_t)info->yPelsPerMeter; + } + else + { + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(image, &xDpi, &yDpi); + *(int32_t*)(ih + 24) = (uint32_t)((double)xDpi * 39.3700787 + 0.5); + *(int32_t*)(ih + 28) = (uint32_t)((double)yDpi * 39.3700787 + 0.5); + } + + uint8_t* data; + HGBase_GetImageData(image, &data); + + if (HGBASE_IMGTYPE_BINARY == type) + { + *(uint32_t*)(fh + 2) = 54 + 4 * 2 + widthStep * height; + *(uint32_t*)(fh + 10) = 54 + 4 * 2; + *(uint16_t*)(ih + 14) = 1; + + uint32_t colorTable[2]; + colorTable[0] = 0x00000000; + colorTable[1] = 0x00FFFFFF; + + fwrite(fh, 14, 1, file); + fwrite(ih, 40, 1, file); + fwrite(colorTable, 4, 2, file); + + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + fwrite(data, 1, widthStep * height, file); + } + else + { + uint8_t* dataEx = data + (height - 1) * widthStep; + while (dataEx >= data) + { + fwrite(dataEx, 1, widthStep, file); + dataEx -= widthStep; + } + } + } + else if (HGBASE_IMGTYPE_GRAY == type) + { + *(uint32_t*)(fh + 2) = 54 + 4 * 256 + widthStep * height; + *(uint32_t*)(fh + 10) = 54 + 4 * 256; + *(uint16_t*)(ih + 14) = 8; + + uint32_t colorTable[256]; + //#pragma omp parallel for + for (int32_t i = 0; i < 256; ++i) + { + uint32_t v = (i & 0x000000FF) | ((i << 8) & 0x0000FF00) | ((i << 16) & 0x00FF0000); + colorTable[i] = v; + } + + fwrite(fh, 14, 1, file); + fwrite(ih, 40, 1, file); + fwrite(colorTable, 4, 256, file); + + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + fwrite(data, 1, widthStep * height, file); + } + else + { + uint8_t* dataEx = data + (height - 1) * widthStep; + while (dataEx >= data) + { + fwrite(dataEx, 1, widthStep, file); + dataEx -= widthStep; + } + } + } + else if (HGBASE_IMGTYPE_RGB == type) + { + *(uint32_t*)(fh + 2) = 54 + widthStep * height; + *(uint32_t*)(fh + 10) = 54; + *(uint16_t*)(ih + 14) = 24; + + fwrite(fh, 14, 1, file); + fwrite(ih, 40, 1, file); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)height; ++i) + { + uint8_t* pEx = data + (uintptr_t)i * (uintptr_t)widthStep; + uint8_t* pExEnd = pEx + width * 3; + uint8_t* pDestEx = buffer + (uintptr_t)i * (uintptr_t)widthStep; + + while (pEx < pExEnd) + { + pDestEx[0] = pEx[2]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[0]; + + pEx += 3; + pDestEx += 3; + } + } + + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + fwrite(buffer, 1, widthStep * height, file); + } + else + { + uint8_t* bufferEx = buffer + (height - 1) * widthStep; + while (bufferEx >= buffer) + { + fwrite(bufferEx, 1, widthStep, file); + bufferEx -= widthStep; + } + } + } + else if (HGBASE_IMGTYPE_BGR == type) + { + *(uint32_t*)(fh + 2) = 54 + widthStep * height; + *(uint32_t*)(fh + 10) = 54; + *(uint16_t*)(ih + 14) = 24; + + fwrite(fh, 14, 1, file); + fwrite(ih, 40, 1, file); + + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + fwrite(data, 1, widthStep * height, file); + } + else + { + uint8_t* dataEx = data + (height - 1) * widthStep; + while (dataEx >= data) + { + fwrite(dataEx, 1, widthStep, file); + dataEx -= widthStep; + } + } + } + else if (HGBASE_IMGTYPE_BGRA == type) + { + *(uint32_t*)(fh + 2) = 54 + widthStep * height; + *(uint32_t*)(fh + 10) = 54; + *(uint16_t*)(ih + 14) = 32; + + fwrite(fh, 14, 1, file); + fwrite(ih, 40, 1, file); + + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + fwrite(data, 1, widthStep * height, file); + } + else + { + uint8_t* dataEx = data + (height - 1) * widthStep; + while (dataEx >= data) + { + fwrite(dataEx, 1, widthStep, file); + dataEx -= widthStep; + } + } + } + else + { + assert(HGBASE_IMGTYPE_RGBA == type); + + *(uint32_t*)(fh + 2) = 54 + widthStep * height; + *(uint32_t*)(fh + 10) = 54; + *(uint16_t*)(ih + 14) = 32; + + fwrite(fh, 14, 1, file); + fwrite(ih, 40, 1, file); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)height; ++i) + { + uint8_t* pEx = data + (uintptr_t)i * (uintptr_t)widthStep; + uint8_t* pExEnd = pEx + width * 4; + uint8_t* pDestEx = buffer + (uintptr_t)i * (uintptr_t)widthStep; + + while (pEx < pExEnd) + { + pDestEx[0] = pEx[2]; + pDestEx[1] = pEx[1]; + pDestEx[2] = pEx[0]; + pDestEx[3] = pEx[3]; + + pEx += 4; + pDestEx += 4; + } + } + + if (HGBASE_IMGORIGIN_BOTTOM == origin) + { + fwrite(buffer, 1, widthStep * height, file); + } + else + { + uint8_t* bufferEx = buffer + (height - 1) * widthStep; + while (bufferEx >= buffer) + { + fwrite(bufferEx, 1, widthStep, file); + bufferEx -= widthStep; + } + } + } + + free(buffer); + buffer = NULL; + fclose(file); + file = NULL; + return HGBASE_ERR_OK; +} diff --git a/app/modules/imgfmt/HGBmp.h b/app/modules/imgfmt/HGBmp.h new file mode 100644 index 0000000..ec59eb3 --- /dev/null +++ b/app/modules/imgfmt/HGBmp.h @@ -0,0 +1,69 @@ +#ifndef __HGBMP_H__ +#define __HGBMP_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +/* 压缩方式 */ +#define HGIMGFMT_BMPENCODING_RGB 0L +#define HGIMGFMT_BMPENCODING_RLE8 1L +#define HGIMGFMT_BMPENCODING_RLE4 2L +#define HGIMGFMT_BMPENCODING_BITFIELDS 3L + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 宽 */ + HGUInt height; /* 高 */ + HGUShort bitCount; /* 每像素比特数 */ + HGUInt compression; /* 压缩方式, 见HGIMGFMT_BMPENCODING_ */ + HGUInt xPelsPerMeter; /* 每米的像素数x */ + HGUInt yPelsPerMeter; /* 每米的像素数y */ +}HGBmpLoadInfo; + +typedef struct +{ + HGUInt xPelsPerMeter; /* 每米的像素数x */ + HGUInt yPelsPerMeter; /* 每米的像素数y */ +}HGBmpSaveInfo; + +#pragma pack(pop) + +/* 检查文件是否是BMP图像 +* 参数: +* 1) fileName: in, 文件名, windows系统上是GBK编码, linux系统上是UTF8编码 +* 2) isBmp: out, 是否是BMP图像 +* 说明: +* 1) 该函数会打开文件判断文件头,而不是判断文件名后缀 +*/ +HGEXPORT HGResult HGAPI HGImgFmt_CheckBmpFile(const HGChar* fileName, HGBool* isBmp); + +/* 加载BMP图像 +* 参数: +* 1) fileName: in, 文件名, windows系统上是GBK编码, linux系统上是UTF8编码 +* 2) info: out, BMP图像加载信息, 如果不需要该信息可传NULL +* 3) imgType: in, 要生成的图像类型, 参见HGBASE_IMGTYPE_*, 传0表示自动获取 +* 4) imgOrigin: in, 要生成的图像数据排列方式, 参见HGBASE_IMGORIGIN_*, 传0表示自动获取 +* 5) image: out, 要生成的图像句柄 +* 说明: +* 1) 生成的图像不使用时需要调用HGBase_DestroyImage销毁 +*/ +HGEXPORT HGResult HGAPI HGImgFmt_LoadBmpImage(const HGChar* fileName, HGBmpLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +/* 保存BMP图像 +* 参数: +* 1) image: in, 要保存的图像句柄 +* 2) info: in, BMP图像保存信息, 如果没有则传NULL +* 3) fileName: in, 文件名, windows系统上是GBK编码, linux系统上是UTF8编码 +* 说明: +* 1) 忽略fileName的文件扩展名 +* 2) 如果info不为NULL, 保存的DPI使用info指定的; 否则使用image自带的 +*/ +HGEXPORT HGResult HGAPI HGImgFmt_SaveBmpImage(HGImage image, const HGBmpSaveInfo* info, const HGChar* fileName); + +#endif /* __HGBMP_H__ */ \ No newline at end of file diff --git a/app/modules/imgfmt/HGGif.cpp b/app/modules/imgfmt/HGGif.cpp new file mode 100644 index 0000000..b37c596 --- /dev/null +++ b/app/modules/imgfmt/HGGif.cpp @@ -0,0 +1,1044 @@ +#include "HGGif.h" +#include "../base/HGInc.h" +#include "../base/HGInfo.h" +#include "gif_lib.h" + +struct HGGifReaderImpl +{ + HGGifReaderImpl() + { + m_gifFile = NULL; + m_curIndex = 0xFFFFFFFF; + m_curInterval = 0xFFFFFFFF; + m_screenBuffer = NULL; + m_imageBuffer = NULL; + } + + ~HGGifReaderImpl() + { + if (NULL != m_imageBuffer) + { + free(m_imageBuffer); + m_imageBuffer = NULL; + } + if (NULL != m_screenBuffer) + { + free(m_screenBuffer); + m_screenBuffer = NULL; + } + if (NULL != m_gifFile) + { + int err; + DGifCloseFile(m_gifFile, &err); + m_gifFile = NULL; + } + } + + GifFileType* m_gifFile; + HGUInt m_curIndex; + HGUInt m_curInterval; + uint8_t* m_screenBuffer; + uint8_t* m_imageBuffer; +}; + +struct HGGifWriterImpl +{ + HGGifWriterImpl() + { + m_initWidth = 0; + m_initHeight = 0; + m_gifFile = NULL; + m_curIndex = 0; + m_redBuffer = NULL; + m_greenBuffer = NULL; + m_blueBuffer = NULL; + } + + ~HGGifWriterImpl() + { + if (NULL != m_blueBuffer) + { + free(m_blueBuffer); + m_blueBuffer = NULL; + } + if (NULL != m_greenBuffer) + { + free(m_greenBuffer); + m_greenBuffer = NULL; + } + if (NULL != m_redBuffer) + { + free(m_redBuffer); + m_redBuffer = NULL; + } + if (NULL != m_gifFile) + { + int savedCount = m_gifFile->ImageCount; + SavedImage* savedImages = m_gifFile->SavedImages; + + //关闭GIF并释放相关存储。 + EGifSpew(m_gifFile); + + for (SavedImage *sp = savedImages; sp < savedImages + savedCount; sp++) + { + if (sp->ImageDesc.ColorMap != NULL) + { + GifFreeMapObject(sp->ImageDesc.ColorMap); + sp->ImageDesc.ColorMap = NULL; + } + + if (sp->RasterBits != NULL) + { + free(sp->RasterBits); + sp->RasterBits = NULL; + } + + GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks); + } + + free(savedImages); + savedImages = NULL; + } + } + + HGUInt m_initWidth; + HGUInt m_initHeight; + GifFileType* m_gifFile; + HGUInt m_curIndex; + uint8_t* m_redBuffer; + uint8_t* m_greenBuffer; + uint8_t* m_blueBuffer; +}; + +#define ABS(x) ((x) > 0 ? (x) : (-(x))) + +#define COLOR_ARRAY_SIZE 32768 +#define BITS_PER_PRIM_COLOR 5 +#define MAX_PRIM_COLOR 0x1f + +static int SortRGBAxis; + +struct QuantizedColorType +{ + GifByteType RGB[3]; + GifByteType NewColorIndex; + long Count; + struct QuantizedColorType* Pnext; +}; + +struct NewColorMapType +{ + GifByteType RGBMin[3], RGBWidth[3]; + unsigned int NumEntries; /* # of QuantizedColorType in linked list below */ + unsigned long Count; /* Total number of pixels in all the entries */ + QuantizedColorType* QuantizedColors; +}; + +static int SortCmpRtn(const void* Entry1, + const void* Entry2) { + QuantizedColorType* entry1 = (*((QuantizedColorType**)Entry1)); + QuantizedColorType* entry2 = (*((QuantizedColorType**)Entry2)); + + /* sort on all axes of the color space! */ + int hash1 = entry1->RGB[SortRGBAxis] * 256 * 256 + + entry1->RGB[(SortRGBAxis + 1) % 3] * 256 + + entry1->RGB[(SortRGBAxis + 2) % 3]; + int hash2 = entry2->RGB[SortRGBAxis] * 256 * 256 + + entry2->RGB[(SortRGBAxis + 1) % 3] * 256 + + entry2->RGB[(SortRGBAxis + 2) % 3]; + + return hash1 - hash2; +} + +static int SubdivColorMap(NewColorMapType* NewColorSubdiv, + unsigned int ColorMapSize, + unsigned int* NewColorMapSize) { + + unsigned int i, j, Index = 0; + QuantizedColorType* QuantizedColor, ** SortArray; + + while (ColorMapSize > *NewColorMapSize) { + /* Find candidate for subdivision: */ + long Sum, Count; + int MaxSize = -1; + unsigned int NumEntries, MinColor, MaxColor; + for (i = 0; i < *NewColorMapSize; i++) { + for (j = 0; j < 3; j++) { + if ((((int)NewColorSubdiv[i].RGBWidth[j]) > MaxSize) && + (NewColorSubdiv[i].NumEntries > 1)) { + MaxSize = NewColorSubdiv[i].RGBWidth[j]; + Index = i; + SortRGBAxis = j; + } + } + } + + if (MaxSize == -1) + return GIF_OK; + + /* Split the entry Index into two along the axis SortRGBAxis: */ + + /* Sort all elements in that entry along the given axis and split at + * the median. */ + SortArray = (QuantizedColorType**)malloc( + sizeof(QuantizedColorType*) * + NewColorSubdiv[Index].NumEntries); + if (SortArray == NULL) + return GIF_ERROR; + for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors; + j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL; + j++, QuantizedColor = QuantizedColor->Pnext) + SortArray[j] = QuantizedColor; + + /* + * Because qsort isn't stable, this can produce differing + * results for the order of tuples depending on platform + * details of how qsort() is implemented. + * + * We mitigate this problem by sorting on all three axes rather + * than only the one specied by SortRGBAxis; that way the instability + * can only become an issue if there are multiple color indices + * referring to identical RGB tuples. Older versions of this + * sorted on only the one axis. + */ + qsort(SortArray, NewColorSubdiv[Index].NumEntries, + sizeof(QuantizedColorType*), SortCmpRtn); + + /* Relink the sorted list into one: */ + for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++) + SortArray[j]->Pnext = SortArray[j + 1]; + SortArray[NewColorSubdiv[Index].NumEntries - 1]->Pnext = NULL; + NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0]; + free((char*)SortArray); + + /* Now simply add the Counts until we have half of the Count: */ + Sum = NewColorSubdiv[Index].Count / 2 - QuantizedColor->Count; + NumEntries = 1; + Count = QuantizedColor->Count; + while (QuantizedColor->Pnext != NULL && + (Sum -= QuantizedColor->Pnext->Count) >= 0 && + QuantizedColor->Pnext->Pnext != NULL) { + QuantizedColor = QuantizedColor->Pnext; + NumEntries++; + Count += QuantizedColor->Count; + } + /* Save the values of the last color of the first half, and first + * of the second half so we can update the Bounding Boxes later. + * Also as the colors are quantized and the BBoxes are full 0..255, + * they need to be rescaled. + */ + MaxColor = QuantizedColor->RGB[SortRGBAxis]; /* Max. of first half */ + /* coverity[var_deref_op] */ + MinColor = QuantizedColor->Pnext->RGB[SortRGBAxis]; /* of second */ + MaxColor <<= (8 - BITS_PER_PRIM_COLOR); + MinColor <<= (8 - BITS_PER_PRIM_COLOR); + + /* Partition right here: */ + NewColorSubdiv[*NewColorMapSize].QuantizedColors = + QuantizedColor->Pnext; + QuantizedColor->Pnext = NULL; + NewColorSubdiv[*NewColorMapSize].Count = Count; + NewColorSubdiv[Index].Count -= Count; + NewColorSubdiv[*NewColorMapSize].NumEntries = + NewColorSubdiv[Index].NumEntries - NumEntries; + NewColorSubdiv[Index].NumEntries = NumEntries; + for (j = 0; j < 3; j++) { + NewColorSubdiv[*NewColorMapSize].RGBMin[j] = + NewColorSubdiv[Index].RGBMin[j]; + NewColorSubdiv[*NewColorMapSize].RGBWidth[j] = + NewColorSubdiv[Index].RGBWidth[j]; + } + NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] = + NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] + + NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] - MinColor; + NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor; + + NewColorSubdiv[Index].RGBWidth[SortRGBAxis] = + MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis]; + + (*NewColorMapSize)++; + } + + return GIF_OK; +} + +static int GifQuantizeBuffer(unsigned int Width, + unsigned int Height, + int* ColorMapSize, + GifByteType* RedInput, + GifByteType* GreenInput, + GifByteType* BlueInput, + GifByteType* OutputBuffer, + GifColorType* OutputColorMap) { + + unsigned int Index, NumOfEntries; + int i, j, MaxRGBError[3]; + unsigned int NewColorMapSize; + long Red, Green, Blue; + NewColorMapType NewColorSubdiv[256]; + QuantizedColorType* ColorArrayEntries, * QuantizedColor; + + ColorArrayEntries = (QuantizedColorType*)malloc( + sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE); + if (ColorArrayEntries == NULL) { + return GIF_ERROR; + } + + for (i = 0; i < COLOR_ARRAY_SIZE; i++) { + ColorArrayEntries[i].RGB[0] = i >> (2 * BITS_PER_PRIM_COLOR); + ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) & + MAX_PRIM_COLOR; + ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR; + ColorArrayEntries[i].Count = 0; + } + + /* Sample the colors and their distribution: */ + for (i = 0; i < (int)(Width * Height); i++) { + Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + (2 * BITS_PER_PRIM_COLOR)) + + ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + BITS_PER_PRIM_COLOR) + + (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR)); + ColorArrayEntries[Index].Count++; + } + + /* Put all the colors in the first entry of the color map, and call the + * recursive subdivision process. */ + for (i = 0; i < 256; i++) { + NewColorSubdiv[i].QuantizedColors = NULL; + NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0; + for (j = 0; j < 3; j++) { + NewColorSubdiv[i].RGBMin[j] = 0; + NewColorSubdiv[i].RGBWidth[j] = 255; + } + } + + /* Find the non empty entries in the color table and chain them: */ + for (i = 0; i < COLOR_ARRAY_SIZE; i++) + if (ColorArrayEntries[i].Count > 0) + break; + QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i]; + NumOfEntries = 1; + while (++i < COLOR_ARRAY_SIZE) + if (ColorArrayEntries[i].Count > 0) { + QuantizedColor->Pnext = &ColorArrayEntries[i]; + QuantizedColor = &ColorArrayEntries[i]; + NumOfEntries++; + } + QuantizedColor->Pnext = NULL; + + NewColorSubdiv[0].NumEntries = NumOfEntries; /* Different sampled colors */ + NewColorSubdiv[0].Count = ((long)Width) * Height; /* Pixels */ + NewColorMapSize = 1; + if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &NewColorMapSize) != + GIF_OK) { + free((char*)ColorArrayEntries); + return GIF_ERROR; + } + if ((int)NewColorMapSize < *ColorMapSize) { + /* And clear rest of color map: */ + for (i = NewColorMapSize; i < *ColorMapSize; i++) + OutputColorMap[i].Red = OutputColorMap[i].Green = + OutputColorMap[i].Blue = 0; + } + + /* Average the colors in each entry to be the color to be used in the + * output color map, and plug it into the output color map itself. */ + for (i = 0; i < (int)NewColorMapSize; i++) { + if ((j = NewColorSubdiv[i].NumEntries) > 0) { + QuantizedColor = NewColorSubdiv[i].QuantizedColors; + Red = Green = Blue = 0; + while (QuantizedColor) { + QuantizedColor->NewColorIndex = i; + Red += QuantizedColor->RGB[0]; + Green += QuantizedColor->RGB[1]; + Blue += QuantizedColor->RGB[2]; + QuantizedColor = QuantizedColor->Pnext; + } + OutputColorMap[i].Red = (GifByteType)((Red << (8 - BITS_PER_PRIM_COLOR)) / j); + OutputColorMap[i].Green = (GifByteType)((Green << (8 - BITS_PER_PRIM_COLOR)) / j); + OutputColorMap[i].Blue = (GifByteType)((Blue << (8 - BITS_PER_PRIM_COLOR)) / j); + } + } + + /* Finally scan the input buffer again and put the mapped index in the + * output buffer. */ + MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0; + for (i = 0; i < (int)(Width * Height); i++) { + Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + (2 * BITS_PER_PRIM_COLOR)) + + ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + BITS_PER_PRIM_COLOR) + + (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR)); + Index = ColorArrayEntries[Index].NewColorIndex; + OutputBuffer[i] = Index; + if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i])) + MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]); + if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i])) + MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]); + if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i])) + MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]); + } + +#ifdef DEBUG + fprintf(stderr, + "Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n", + MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]); +#endif /* DEBUG */ + + free((char*)ColorArrayEntries); + + *ColorMapSize = NewColorMapSize; + + return GIF_OK; +} + +HGResult HGAPI HGImgFmt_CheckGifFile(const HGChar* fileName, HGBool* isGif) +{ + if (NULL == fileName || NULL == isGif) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + if (0 != _access(fileName, 0)) +#else + if (0 != access(fileName, 0)) +#endif + { + return HGBASE_ERR_FILENOTEXIST; + } + + int err; + GifFileType* gifFile = DGifOpenFileName(fileName, &err); + if (NULL == gifFile) + { + return HGBASE_ERR_FILEERROR; + } + + *isGif = HGTRUE; + DGifCloseFile(gifFile, &err); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_OpenGifReader(const HGChar* fileName, HGGifLoadInfo* info, HGGifReader* reader) +{ + if (NULL == fileName || NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + if (0 != _access(fileName, 0)) +#else + if (0 != access(fileName, 0)) +#endif + { + return HGBASE_ERR_FILENOTEXIST; + } + + int err; + GifFileType* gifFile = DGifOpenFileName(fileName, &err); + if (NULL == gifFile) + { + return HGBASE_ERR_FILEERROR; + } + + DGifSlurp(gifFile); + if (gifFile->ImageCount <= 0) + { + DGifCloseFile(gifFile, &err); + return HGBASE_ERR_FILEERROR; + } + + uint8_t* screenBuffer = (uint8_t*)malloc(gifFile->SWidth * gifFile->SHeight); + if (NULL == screenBuffer) + { + DGifCloseFile(gifFile, &err); + return HGBASE_ERR_OUTOFMEMORY; + } + + uint8_t* imageBuffer = (uint8_t *)malloc(gifFile->SWidth * gifFile->SHeight * 4); + if (NULL == imageBuffer) + { + free(screenBuffer); + screenBuffer = NULL; + DGifCloseFile(gifFile, &err); + return HGBASE_ERR_OUTOFMEMORY; + } + + // 设置底色 + memset(screenBuffer, gifFile->SBackGroundColor, gifFile->SWidth * gifFile->SHeight); + + if (NULL != info) + { + info->width = gifFile->SWidth; + info->height = gifFile->SHeight; + info->colorResolution = gifFile->SColorResolution; + info->imageCount = gifFile->ImageCount; + } + + HGGifReaderImpl* gifReaderImpl = new HGGifReaderImpl; + gifReaderImpl->m_gifFile = gifFile; + gifReaderImpl->m_screenBuffer = screenBuffer; + gifReaderImpl->m_imageBuffer = imageBuffer; + + *reader = (HGGifReader)gifReaderImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_CloseGifReader(HGGifReader reader) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGGifReaderImpl* gifReaderImpl = (HGGifReaderImpl*)reader; + delete gifReaderImpl; + return HGBASE_ERR_OK; +} + +static HGResult LoadGifImage(HGGifReaderImpl* gifReaderImpl) +{ + assert(NULL != gifReaderImpl); + + int transColor = -1; + unsigned int loopCount = 0; + + SavedImage* image = &gifReaderImpl->m_gifFile->SavedImages[gifReaderImpl->m_curIndex]; + + //获取间隔、TransparentColor等信息 + for (ExtensionBlock* ep = image->ExtensionBlocks; ep < image->ExtensionBlocks + image->ExtensionBlockCount; ep++) + { + bool last = (ep - image->ExtensionBlocks == (image->ExtensionBlockCount - 1)); + if (ep->Function == GRAPHICS_EXT_FUNC_CODE) + { + GraphicsControlBlock gcb; + if (DGifExtensionToGCB(ep->ByteCount, ep->Bytes, &gcb) == GIF_ERROR) + { + return HGIMGFMT_ERR_FAIL; + } + + transColor = gcb.TransparentColor; + //DelayTime的单位为10 ms + gifReaderImpl->m_curInterval = gcb.DelayTime * 10; + } + else if (!last + && ep->Function == APPLICATION_EXT_FUNC_CODE + && ep->ByteCount >= 11 + && (ep + 1)->ByteCount >= 3 + && memcmp(ep->Bytes, "NETSCAPE2.0", 11) == 0) + { + unsigned char* params = (++ep)->Bytes; + loopCount = params[1] | (params[2] << 8); + } + else + { + //其他信息暂不处理 + while (!last && ep[1].Function == CONTINUE_EXT_FUNC_CODE) + { + ++ep; + last = (ep - image->ExtensionBlocks == (image->ExtensionBlockCount - 1)); + } + } + } + + if (image->ImageDesc.Interlace) + { + // + } + + ColorMapObject* colorMap = (image->ImageDesc.ColorMap ? image->ImageDesc.ColorMap : gifReaderImpl->m_gifFile->SColorMap); + if (colorMap == NULL) + { + return HGIMGFMT_ERR_FAIL; + } + + for (int h = image->ImageDesc.Top; h < image->ImageDesc.Top + image->ImageDesc.Height; ++h) + { + uint8_t* p1 = gifReaderImpl->m_screenBuffer + h * gifReaderImpl->m_gifFile->SWidth + image->ImageDesc.Left; + uint8_t* p2 = image->RasterBits + (h - image->ImageDesc.Top) * image->ImageDesc.Width; + memcpy(p1, p2, image->ImageDesc.Width); + } + + for (int h = 0; h < gifReaderImpl->m_gifFile->SHeight; ++h) + { + uint8_t* p1 = gifReaderImpl->m_imageBuffer + h * gifReaderImpl->m_gifFile->SWidth * 4; + uint8_t* p2 = gifReaderImpl->m_screenBuffer + h * gifReaderImpl->m_gifFile->SWidth; + for (int w = 0; w < gifReaderImpl->m_gifFile->SWidth; ++w) + { + if (transColor != -1 && transColor == p2[w]) + continue; + + GifColorType* colorMapEntry = &colorMap->Colors[p2[w]]; + p1[w * 4] = colorMapEntry->Red; + p1[w * 4 + 1] = colorMapEntry->Green; + p1[w * 4 + 2] = colorMapEntry->Blue; + p1[w * 4 + 3] = 0xFF; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_RetrieveImageFromGifReader(HGGifReader reader, HGUInt* index, HGUInt* interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == reader || NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgType && HGBASE_IMGTYPE_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType + && HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType + && HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + + HGGifReaderImpl* gifReaderImpl = (HGGifReaderImpl*)reader; + if (gifReaderImpl->m_curIndex + 1 >= (HGUInt)gifReaderImpl->m_gifFile->ImageCount) + { + gifReaderImpl->m_curIndex = 0xFFFFFFFF; + // 设置底色 + memset(gifReaderImpl->m_screenBuffer, gifReaderImpl->m_gifFile->SBackGroundColor, + gifReaderImpl->m_gifFile->SWidth * gifReaderImpl->m_gifFile->SHeight); + } + + ++gifReaderImpl->m_curIndex; + + HGResult ret = LoadGifImage(gifReaderImpl); + if (HGBASE_ERR_OK != ret) + { + --gifReaderImpl->m_curIndex; + return ret; + } + + if (0 == imgType) + { + imgType = HGBASE_IMGTYPE_RGB; + } + + if (0 == imgOrigin) + { + imgOrigin = HGBASE_IMGORIGIN_TOP; + } + + HGImageInfo gifImageInfo; + gifImageInfo.width = gifReaderImpl->m_gifFile->SWidth; + gifImageInfo.height = gifReaderImpl->m_gifFile->SHeight; + gifImageInfo.type = HGBASE_IMGTYPE_RGBA; + gifImageInfo.widthStep = gifReaderImpl->m_gifFile->SWidth * 4; + gifImageInfo.origin = HGBASE_IMGORIGIN_TOP; + + HGImage image2 = NULL; + ret = HGBase_CreateImageWithData((HGByte*)gifReaderImpl->m_imageBuffer, &gifImageInfo, &image2); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); + HGBase_DestroyImage(image2); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != index) + *index = gifReaderImpl->m_curIndex; + if (NULL != interval) + *interval = gifReaderImpl->m_curInterval; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_LoadImageFromGifReader(HGGifReader reader, HGUInt index, HGUInt* interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == reader || NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgType && HGBASE_IMGTYPE_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType + && HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType + && HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + + HGGifReaderImpl* gifReaderImpl = (HGGifReaderImpl*)reader; + if (index >= (HGUInt)gifReaderImpl->m_gifFile->ImageCount) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == imgType) + { + imgType = HGBASE_IMGTYPE_RGB; + } + + if (imgOrigin == 0) + { + imgOrigin = HGBASE_IMGORIGIN_TOP; + } + + if (index < gifReaderImpl->m_curIndex) + { + gifReaderImpl->m_curIndex = 0xFFFFFFFF; + // 设置底色 + memset(gifReaderImpl->m_screenBuffer, gifReaderImpl->m_gifFile->SBackGroundColor, + gifReaderImpl->m_gifFile->SWidth * gifReaderImpl->m_gifFile->SHeight); + } + + while (index != gifReaderImpl->m_curIndex) + { + ++gifReaderImpl->m_curIndex; + + HGResult ret = LoadGifImage(gifReaderImpl); + if (HGBASE_ERR_OK != ret) + { + --gifReaderImpl->m_curIndex; + return ret; + } + } + + HGImageInfo gifImageInfo; + gifImageInfo.width = gifReaderImpl->m_gifFile->SWidth; + gifImageInfo.height = gifReaderImpl->m_gifFile->SHeight; + gifImageInfo.type = HGBASE_IMGTYPE_RGBA; + gifImageInfo.widthStep = gifReaderImpl->m_gifFile->SWidth * 4; + gifImageInfo.origin = HGBASE_IMGORIGIN_TOP; + + HGImage image2 = NULL; + HGResult ret = HGBase_CreateImageWithData((HGByte*)gifReaderImpl->m_imageBuffer, &gifImageInfo, &image2); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); + HGBase_DestroyImage(image2); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != interval) + *interval = gifReaderImpl->m_curInterval; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_LoadGifImage(const HGChar* fileName, HGGifLoadInfo* info, HGUInt* interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == image) + { + if (NULL != interval || 0 != imgType || 0 != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + + HGGifReader reader = NULL; + HGResult ret = HGImgFmt_OpenGifReader(fileName, info, &reader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != image) + { + ret = HGImgFmt_RetrieveImageFromGifReader(reader, NULL, interval, imgType, imgOrigin, image); + } + + HGImgFmt_CloseGifReader(reader); + return ret; +} + +HGResult HGAPI HGImgFmt_OpenGifWriter(const HGChar* fileName, const HGGifSaveInfo* info, HGGifWriter* writer) +{ + if (NULL == fileName || NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + int err; + GifFileType* gifFile = EGifOpenFileName(fileName, false, &err); + if (NULL == gifFile) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGImgFmt_OpenGifWriter: EGifOpenFileName fail, %s", fileName); + return HGBASE_ERR_ACCESSDENIED; + } + + gifFile->SWidth = 0; + gifFile->SHeight = 0; + gifFile->SColorResolution = 8; + gifFile->SBackGroundColor = 0; + gifFile->SColorMap = NULL; + gifFile->SavedImages = NULL; + gifFile->ImageCount = 0; + gifFile->ExtensionBlockCount = 0; + gifFile->ExtensionBlocks = NULL; + + HGGifWriterImpl* gifWriterImpl = new HGGifWriterImpl; + gifWriterImpl->m_initWidth = (NULL != info) ? info->width : 0; + gifWriterImpl->m_initHeight = (NULL != info) ? info->height : 0; + gifWriterImpl->m_gifFile = gifFile; + gifWriterImpl->m_curIndex = 0; + gifWriterImpl->m_redBuffer = NULL; + gifWriterImpl->m_greenBuffer = NULL; + gifWriterImpl->m_blueBuffer = NULL; + + *writer = (HGGifWriter)gifWriterImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_CloseGifWriter(HGGifWriter writer) +{ + if (NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGGifWriterImpl* gifWriterImpl = (HGGifWriterImpl*)writer; + delete gifWriterImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveImageToGifWriter(HGGifWriter writer, HGUInt interval, HGColor bkColor, HGImage image) +{ + if (NULL == writer || NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGBase_ResetImageROI(image); + + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgFmt_SaveImageToGifWriter(writer, interval, bkColor, imageTmp); + HGBase_DestroyImage(imageTmp); + } + + HGBase_SetImageROI(image, &roi); + return ret; + } + + HGGifWriterImpl* gifWriterImpl = (HGGifWriterImpl*)writer; + if (0 == gifWriterImpl->m_curIndex) + { + gifWriterImpl->m_gifFile->SWidth = (0 == gifWriterImpl->m_initWidth) + ? imgInfo.width : gifWriterImpl->m_initWidth; + gifWriterImpl->m_gifFile->SHeight = (0 == gifWriterImpl->m_initHeight) + ? imgInfo.height : gifWriterImpl->m_initHeight; + + free(gifWriterImpl->m_redBuffer); + gifWriterImpl->m_redBuffer = (uint8_t*)malloc(gifWriterImpl->m_gifFile->SWidth * gifWriterImpl->m_gifFile->SHeight); + if (NULL == gifWriterImpl->m_redBuffer) + { + return HGBASE_ERR_OUTOFMEMORY; + } + + free(gifWriterImpl->m_greenBuffer); + gifWriterImpl->m_greenBuffer = (uint8_t*)malloc(gifWriterImpl->m_gifFile->SWidth * gifWriterImpl->m_gifFile->SHeight); + if (NULL == gifWriterImpl->m_greenBuffer) + { + free(gifWriterImpl->m_redBuffer); + gifWriterImpl->m_redBuffer = NULL; + return HGBASE_ERR_OUTOFMEMORY; + } + + free(gifWriterImpl->m_blueBuffer); + gifWriterImpl->m_blueBuffer = (uint8_t*)malloc(gifWriterImpl->m_gifFile->SWidth * gifWriterImpl->m_gifFile->SHeight); + if (NULL == gifWriterImpl->m_blueBuffer) + { + free(gifWriterImpl->m_greenBuffer); + gifWriterImpl->m_greenBuffer = NULL; + free(gifWriterImpl->m_redBuffer); + gifWriterImpl->m_redBuffer = NULL; + return HGBASE_ERR_OUTOFMEMORY; + } + } + + GifFileType* gifFile = gifWriterImpl->m_gifFile; + GifWord gifWidth = gifWriterImpl->m_gifFile->SWidth; + GifWord gifHeight = gifWriterImpl->m_gifFile->SHeight; + uint8_t* redBuffer = gifWriterImpl->m_redBuffer; + uint8_t* greenBuffer = gifWriterImpl->m_greenBuffer; + uint8_t* blueBuffer = gifWriterImpl->m_blueBuffer; + + memset(redBuffer, HG_GETCOLOR_R(bkColor), gifWidth * gifHeight); + memset(greenBuffer, HG_GETCOLOR_G(bkColor), gifWidth * gifHeight); + memset(blueBuffer, HG_GETCOLOR_B(bkColor), gifWidth * gifHeight); + + HGByte* imgData = NULL; + HGBase_GetImageData(image, &imgData); + + int channels = 1; + if (HGBASE_IMGTYPE_RGB == imgInfo.type || HGBASE_IMGTYPE_BGR == imgInfo.type) + channels = 3; + else if (HGBASE_IMGTYPE_RGBA == imgInfo.type || HGBASE_IMGTYPE_BGRA == imgInfo.type) + channels = 4; + + int copyWidth = HGMIN((GifWord)imgInfo.width, gifWidth); + int copyHeight = HGMIN((GifWord)imgInfo.height, gifHeight); + int srcLeft = ((GifWord)imgInfo.width <= gifWidth) ? 0 : ((GifWord)imgInfo.width - gifWidth) / 2; + int srcTop = ((GifWord)imgInfo.height <= gifHeight) ? 0 : ((GifWord)imgInfo.height - gifHeight) / 2; + int dstLeft = ((GifWord)imgInfo.width <= gifWidth) ? (gifWidth - (GifWord)imgInfo.width) / 2 : 0; + int dstTop = ((GifWord)imgInfo.height <= gifHeight) ? (gifHeight - (GifWord)imgInfo.height) / 2 : 0; + + if (HGBASE_IMGTYPE_RGB == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type) + { + for (int row = 0; row < copyHeight; row++) + { + uint8_t* pr = redBuffer + (row + dstTop) * gifWidth; + uint8_t* pg = greenBuffer + (row + dstTop) * gifWidth; + uint8_t* pb = blueBuffer + (row + dstTop) * gifWidth; + uint8_t* pData = imgData + (row + srcTop) * imgInfo.widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + pData = imgData + (imgInfo.height - row - srcTop - 1) * imgInfo.widthStep; + + for (int col = 0; col < copyWidth; col++) + { + pr[col + dstLeft] = pData[(col + srcLeft) * channels]; + pg[col + dstLeft] = pData[(col + srcLeft) * channels + 1]; + pb[col + dstLeft] = pData[(col + srcLeft) * channels + 2]; + } + } + } + else if (HGBASE_IMGTYPE_BGR == imgInfo.type || HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + for (int row = 0; row < copyHeight; row++) + { + uint8_t* pr = redBuffer + (row + dstTop) * gifWidth; + uint8_t* pg = greenBuffer + (row + dstTop) * gifWidth; + uint8_t* pb = blueBuffer + (row + dstTop) * gifWidth; + uint8_t* pData = imgData + (row + srcTop) * imgInfo.widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + pData = imgData + (imgInfo.height - row - srcTop - 1) * imgInfo.widthStep; + + for (int col = 0; col < copyWidth; col++) + { + pb[col + dstLeft] = pData[(col + srcLeft) * channels]; + pg[col + dstLeft] = pData[(col + srcLeft) * channels + 1]; + pr[col + dstLeft] = pData[(col + srcLeft) * channels + 2]; + } + } + } + else + { + assert(HGBASE_IMGTYPE_GRAY == imgInfo.type); + + for (int row = 0; row < copyHeight; row++) + { + uint8_t* pr = redBuffer + (row + dstTop) * gifWidth; + uint8_t* pg = greenBuffer + (row + dstTop) * gifWidth; + uint8_t* pb = blueBuffer + (row + dstTop) * gifWidth; + uint8_t* pData = imgData + (row + srcTop) * imgInfo.widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + pData = imgData + (imgInfo.height - row - srcTop - 1) * imgInfo.widthStep; + + for (int col = 0; col < copyWidth; col++) + { + pr[col + dstLeft] = pData[(col + srcLeft)]; + pg[col + dstLeft] = pData[(col + srcLeft)]; + pb[col + dstLeft] = pData[(col + srcLeft)]; + } + } + } + + int mapSize = (1 << gifFile->SColorResolution); + ColorMapObject* colorMap = GifMakeMapObject(mapSize, NULL); + if (NULL == colorMap) + { + return HGIMGFMT_ERR_FAIL; + } + + GifByteType* rasterBits = (GifPixelType*)malloc(sizeof(GifPixelType) * gifWidth * gifHeight); + if (NULL == rasterBits) + { + GifFreeMapObject(colorMap); + return HGBASE_ERR_OUTOFMEMORY; + } + + if (GifQuantizeBuffer(gifWidth, gifHeight, &mapSize, redBuffer, greenBuffer, blueBuffer, + rasterBits, colorMap->Colors) == GIF_ERROR) + { + free(rasterBits); + GifFreeMapObject(colorMap); + return HGIMGFMT_ERR_FAIL; + } + + SavedImage* gifImage = GifMakeSavedImage(gifFile, NULL); + if (NULL == gifImage) + { + free(rasterBits); + GifFreeMapObject(colorMap); + return HGIMGFMT_ERR_FAIL; + } + + gifImage->ImageDesc.Left = 0; + gifImage->ImageDesc.Top = 0; + gifImage->ImageDesc.Width = gifWidth; + gifImage->ImageDesc.Height = gifHeight; + gifImage->ImageDesc.Interlace = false; + gifImage->ImageDesc.ColorMap = colorMap; + gifImage->RasterBits = rasterBits; + + GraphicsControlBlock gcb; + gcb.DisposalMode = DISPOSAL_UNSPECIFIED; + gcb.DelayTime = interval / 10; + gcb.UserInputFlag = false; + gcb.TransparentColor = NO_TRANSPARENT_COLOR; + EGifGCBToSavedExtension(&gcb, gifFile, gifWriterImpl->m_curIndex); + + //把循环次数写到第一帧对应的扩展块 + if (0 == gifWriterImpl->m_curIndex) + { + //Create a Netscape 2.0 loop block + GifAddExtensionBlock(&gifImage->ExtensionBlockCount, &gifImage->ExtensionBlocks, + APPLICATION_EXT_FUNC_CODE, 11, (unsigned char*)"NETSCAPE2.0"); + + unsigned char params[3] = { 1, 0, 0 }; + GifAddExtensionBlock(&gifImage->ExtensionBlockCount, &gifImage->ExtensionBlocks, + CONTINUE_EXT_FUNC_CODE, sizeof(params), params); + } + + ++gifWriterImpl->m_curIndex; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveGifImage(HGImage image, const HGGifSaveInfo* info, + HGUInt interval, HGColor bkColor, const HGChar* fileName) +{ + HGGifWriter writer = NULL; + HGResult ret = HGImgFmt_OpenGifWriter(fileName, info, &writer); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGImgFmt_SaveImageToGifWriter(writer, interval, bkColor, image); + HGImgFmt_CloseGifWriter(writer); + return ret; +} \ No newline at end of file diff --git a/app/modules/imgfmt/HGGif.h b/app/modules/imgfmt/HGGif.h new file mode 100644 index 0000000..b0ae138 --- /dev/null +++ b/app/modules/imgfmt/HGGif.h @@ -0,0 +1,55 @@ +#ifndef __HGGIF_H__ +#define __HGGIF_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +HG_DECLARE_HANDLE(HGGifReader); +HG_DECLARE_HANDLE(HGGifWriter); + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUInt colorResolution; /* 位深 */ + HGUInt imageCount; /* 图像数量 */ +}HGGifLoadInfo; + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ +}HGGifSaveInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckGifFile(const HGChar* fileName, HGBool* isGif); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenGifReader(const HGChar* fileName, HGGifLoadInfo* info, HGGifReader* reader); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseGifReader(HGGifReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_RetrieveImageFromGifReader(HGGifReader reader, HGUInt *index, HGUInt *interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromGifReader(HGGifReader reader, HGUInt index, HGUInt* interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadGifImage(const HGChar* fileName, HGGifLoadInfo* info, HGUInt* interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenGifWriter(const HGChar* fileName, const HGGifSaveInfo* info, HGGifWriter* writer); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseGifWriter(HGGifWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveImageToGifWriter(HGGifWriter writer, HGUInt interval, HGColor bkColor, HGImage image); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveGifImage(HGImage image, const HGGifSaveInfo* info, + HGUInt interval, HGColor bkColor, const HGChar* fileName); + +#endif /* __HGGIF_H__ */ \ No newline at end of file diff --git a/app/modules/imgfmt/HGImgFmt.cpp b/app/modules/imgfmt/HGImgFmt.cpp new file mode 100644 index 0000000..c2b4fcd --- /dev/null +++ b/app/modules/imgfmt/HGImgFmt.cpp @@ -0,0 +1,1486 @@ +#include "HGImgFmt.h" +#include "HGJpeg.h" +#include "HGBmp.h" +#include "HGPng.h" +#include "HGTiff.h" +#include "HGPdf.h" +#include "HGOfd.h" +#include "HGGif.h" +#include "HGPnm.h" +#include "../base/HGInc.h" +#include + +struct HGImgFmtReaderImpl +{ + HGImgFmtReaderImpl() + { + fmtType = 0; + handle = NULL; + } + + std::string fileName; + HGUInt fmtType; + HGPointer handle; + HGGifLoadInfo gifLoadInfo; +}; + +struct HGImgFmtWriterImpl +{ + HGImgFmtWriterImpl() + { + fmtType = 0; + handle = NULL; + write = HGFALSE; + } + + std::string fileName; + HGUInt fmtType; + HGPointer handle; + HGBool write; // 用于标记JPEG、BMP、PNG和PNM是否已经写入 +}; + +HGResult HGAPI HGImgFmt_GetImgFmtType(const HGChar* fileName, HGUInt* fmtType) +{ + if (NULL == fileName || NULL == fmtType) + { + return HGBASE_ERR_INVALIDARG; + } + + HGBool isJpeg = HGFALSE; + HGResult ret = HGImgFmt_CheckJpegFile(fileName, &isJpeg); + if (isJpeg) + { + *fmtType = HGIMGFMT_TYPE_JPEG; + return HGBASE_ERR_OK; + } + + HGBool isBmp = HGFALSE; + ret = HGImgFmt_CheckBmpFile(fileName, &isBmp); + if (isBmp) + { + *fmtType = HGIMGFMT_TYPE_BMP; + return HGBASE_ERR_OK; + } + + HGBool isPng = HGFALSE; + ret = HGImgFmt_CheckPngFile(fileName, &isPng); + if (isPng) + { + *fmtType = HGIMGFMT_TYPE_PNG; + return HGBASE_ERR_OK; + } + + HGBool isTiff = HGFALSE; + ret = HGImgFmt_CheckTiffFile(fileName, &isTiff); + if (isTiff) + { + *fmtType = HGIMGFMT_TYPE_TIFF; + return HGBASE_ERR_OK; + } + + HGBool isPdf = HGFALSE; + ret = HGImgFmt_CheckPdfFile(fileName, &isPdf); + if (isPdf) + { + *fmtType = HGIMGFMT_TYPE_PDF; + return HGBASE_ERR_OK; + } + + HGBool isOfd = HGFALSE; + ret = HGImgFmt_CheckOfdFile(fileName, &isOfd); + if (isOfd) + { + *fmtType = HGIMGFMT_TYPE_OFD; + return HGBASE_ERR_OK; + } + + HGBool isGif = HGFALSE; + ret = HGImgFmt_CheckGifFile(fileName, &isGif); + if (isGif) + { + *fmtType = HGIMGFMT_TYPE_GIF; + return HGBASE_ERR_OK; + } + + HGBool isPnm = HGFALSE; + ret = HGImgFmt_CheckPnmFile(fileName, &isPnm); + if (isPnm) + { + *fmtType = HGIMGFMT_TYPE_PNM; + return HGBASE_ERR_OK; + } + + return ret; +} + +HGResult HGAPI HGImgFmt_GetImgFmtTypeFromFileName(const HGChar* fileName, HGUInt* fmtType) +{ + if (NULL == fileName || NULL == fmtType) + { + return HGBASE_ERR_INVALIDARG; + } + + const char* p = strrchr(fileName, '.'); + if (NULL == p) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + if (0 == _stricmp(p, ".jpe") || 0 == _stricmp(p, ".jpg") || 0 == _stricmp(p, ".jpeg")) + { + *fmtType = HGIMGFMT_TYPE_JPEG; + return HGBASE_ERR_OK; + } + + if (0 == _stricmp(p, ".bmp") || 0 == _stricmp(p, ".dib")) + { + *fmtType = HGIMGFMT_TYPE_BMP; + return HGBASE_ERR_OK; + } + + if (0 == _stricmp(p, ".png")) + { + *fmtType = HGIMGFMT_TYPE_PNG; + return HGBASE_ERR_OK; + } + + if (0 == _stricmp(p, ".tif") || 0 == _stricmp(p, ".tiff")) + { + *fmtType = HGIMGFMT_TYPE_TIFF; + return HGBASE_ERR_OK; + } + + if (0 == _stricmp(p, ".pdf")) + { + *fmtType = HGIMGFMT_TYPE_PDF; + return HGBASE_ERR_OK; + } + + if (0 == _stricmp(p, ".ofd")) + { + *fmtType = HGIMGFMT_TYPE_OFD; + return HGBASE_ERR_OK; + } + + if (0 == _stricmp(p, ".gif")) + { + *fmtType = HGIMGFMT_TYPE_GIF; + return HGBASE_ERR_OK; + } + + if (0 == _stricmp(p, ".pbm") || 0 == _stricmp(p, ".pgm") || 0 == _stricmp(p, ".ppm")) + { + *fmtType = HGIMGFMT_TYPE_PNM; + return HGBASE_ERR_OK; + } +#else + if (0 == strcasecmp(p, ".jpe") || 0 == strcasecmp(p, ".jpg") || 0 == strcasecmp(p, ".jpeg")) + { + *fmtType = HGIMGFMT_TYPE_JPEG; + return HGBASE_ERR_OK; + } + + if (0 == strcasecmp(p, ".bmp") || 0 == strcasecmp(p, ".dib")) + { + *fmtType = HGIMGFMT_TYPE_BMP; + return HGBASE_ERR_OK; + } + + if (0 == strcasecmp(p, ".png")) + { + *fmtType = HGIMGFMT_TYPE_PNG; + return HGBASE_ERR_OK; + } + + if (0 == strcasecmp(p, ".tif") || 0 == strcasecmp(p, ".tiff")) + { + *fmtType = HGIMGFMT_TYPE_TIFF; + return HGBASE_ERR_OK; + } + + if (0 == strcasecmp(p, ".pdf")) + { + *fmtType = HGIMGFMT_TYPE_PDF; + return HGBASE_ERR_OK; + } + + if (0 == strcasecmp(p, ".ofd")) + { + *fmtType = HGIMGFMT_TYPE_OFD; + return HGBASE_ERR_OK; + } + + if (0 == strcasecmp(p, ".gif")) + { + *fmtType = HGIMGFMT_TYPE_GIF; + return HGBASE_ERR_OK; + } + + if (0 == strcasecmp(p, ".pbm") || 0 == strcasecmp(p, ".pgm") || 0 == strcasecmp(p, ".ppm")) + { + *fmtType = HGIMGFMT_TYPE_PNM; + return HGBASE_ERR_OK; + } +#endif + + return HGBASE_ERR_FAIL; +} + +HGResult HGAPI HGImgFmt_IsMultiImgFmtType(HGUInt fmtType, HGBool* isMulti) +{ + if (fmtType < HGIMGFMT_TYPE_JPEG || fmtType > HGIMGFMT_TYPE_PNM || NULL == isMulti) + { + return HGBASE_ERR_INVALIDARG; + } + + if (HGIMGFMT_TYPE_JPEG == fmtType || HGIMGFMT_TYPE_BMP == fmtType || HGIMGFMT_TYPE_PNG == fmtType + || HGIMGFMT_TYPE_PNM == fmtType) + *isMulti = HGFALSE; + else + *isMulti = HGTRUE; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_LoadImage(const HGChar* fileName, HGUInt fmtType, HGImgFmtLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (fmtType > HGIMGFMT_TYPE_PNM) + { + return HGBASE_ERR_INVALIDARG; + } + + if (HGIMGFMT_TYPE_JPEG == fmtType) + { + HGJpegLoadInfo jpegInfo; + HGResult ret = HGImgFmt_LoadJpegImage(fileName, &jpegInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = jpegInfo.width; + info->height = jpegInfo.height; + info->bpp = jpegInfo.numComponents * 8; + info->xDpi = 0; + info->yDpi = 0; + if (HGIMGFMT_JPEGDENUNIT_INCH == jpegInfo.densityUnit) + { + info->xDpi = jpegInfo.xDensity; + info->yDpi = jpegInfo.yDensity; + } + else if (HGIMGFMT_JPEGDENUNIT_CENTIMETER == jpegInfo.densityUnit) + { + info->xDpi = (uint32_t)((double)jpegInfo.xDensity / 0.393700787 + 0.5); + info->yDpi = (uint32_t)((double)jpegInfo.yDensity / 0.393700787 + 0.5); + } + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_BMP == fmtType) + { + HGBmpLoadInfo bmpInfo; + HGResult ret = HGImgFmt_LoadBmpImage(fileName, &bmpInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = bmpInfo.width; + info->height = bmpInfo.height; + info->bpp = bmpInfo.bitCount; + info->xDpi = (uint32_t)((double)bmpInfo.xPelsPerMeter / 39.3700787 + 0.5); + info->yDpi = (uint32_t)((double)bmpInfo.yPelsPerMeter / 39.3700787 + 0.5); + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_PNG == fmtType) + { + HGPngLoadInfo pngInfo; + HGResult ret = HGImgFmt_LoadPngImage(fileName, &pngInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = pngInfo.width; + info->height = pngInfo.height; + info->bpp = pngInfo.pixelDepth; + info->xDpi = 0; + info->yDpi = 0; + if (HGIMGFMT_PNGPHYSUNIT_METER == pngInfo.physUnitType) + { + info->xDpi = (uint32_t)((double)pngInfo.xPixelsPerUnit / 39.3700787 + 0.5); + info->yDpi = (uint32_t)((double)pngInfo.yPixelsPerUnit / 39.3700787 + 0.5); + } + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_TIFF == fmtType) + { + HGTiffLoadInfo tiffInfo; + HGResult ret = HGImgFmt_LoadTiffImage(fileName, &tiffInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = tiffInfo.width; + info->height = tiffInfo.height; + info->bpp = tiffInfo.bitsPerSample * tiffInfo.samplesPerPixel; + info->xDpi = 0; + info->yDpi = 0; + if (HGIMGFMT_TIFFRESUNIT_INCH == tiffInfo.resolutionUnit) + { + info->xDpi = (uint32_t)(tiffInfo.xResolution + 0.5f); + info->yDpi = (uint32_t)(tiffInfo.yResolution + 0.5f); + } + else if (HGIMGFMT_TIFFRESUNIT_CENTIMETER == tiffInfo.resolutionUnit) + { + info->xDpi = (uint32_t)((double)tiffInfo.xResolution / 0.393700787 + 0.5); + info->yDpi = (uint32_t)((double)tiffInfo.yResolution / 0.393700787 + 0.5); + } + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_PDF == fmtType) + { + HGPdfPageInfo pdfInfo; + HGResult ret = HGImgFmt_LoadPdfImage(fileName, &pdfInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = pdfInfo.width; + info->height = pdfInfo.height; + info->bpp = pdfInfo.bpp; + info->xDpi = 0; + info->yDpi = 0; + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_OFD == fmtType) + { + HGOfdPageInfo ofdInfo; + HGResult ret = HGImgFmt_LoadOfdImage(fileName, &ofdInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = ofdInfo.width; + info->height = ofdInfo.height; + info->bpp = ofdInfo.bpp; + info->xDpi = 0; + info->yDpi = 0; + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_GIF == fmtType) + { + HGGifLoadInfo gifInfo; + HGResult ret = HGImgFmt_LoadGifImage(fileName, &gifInfo, NULL, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = gifInfo.width; + info->height = gifInfo.height; + info->bpp = gifInfo.colorResolution; + info->xDpi = 0; + info->yDpi = 0; + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_PNM == fmtType) + { + HGPnmLoadInfo pnmInfo; + HGResult ret = HGImgFmt_LoadPnmImage(fileName, &pnmInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = pnmInfo.width; + info->height = pnmInfo.height; + info->bpp = 1; + if (pnmInfo.type == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmInfo.type == HGIMGFMT_PNMTYPE_GRAY_BINARY) + info->bpp = 8; + else if (pnmInfo.type == HGIMGFMT_PNMTYPE_RGB_ASCII || pnmInfo.type == HGIMGFMT_PNMTYPE_RGB_BINARY) + info->bpp = 24; + info->xDpi = 0; + info->yDpi = 0; + } + + return HGBASE_ERR_OK; + } + + assert(0 == fmtType); + + HGJpegLoadInfo jpegInfo; + HGResult ret = HGImgFmt_LoadJpegImage(fileName, &jpegInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK == ret) + { + if (NULL != info) + { + info->width = jpegInfo.width; + info->height = jpegInfo.height; + info->bpp = jpegInfo.numComponents * 8; + info->xDpi = 0; + info->yDpi = 0; + if (HGIMGFMT_JPEGDENUNIT_INCH == jpegInfo.densityUnit) + { + info->xDpi = jpegInfo.xDensity; + info->yDpi = jpegInfo.yDensity; + } + else if (HGIMGFMT_JPEGDENUNIT_CENTIMETER == jpegInfo.densityUnit) + { + info->xDpi = (uint32_t)((double)jpegInfo.xDensity / 0.393700787 + 0.5); + info->yDpi = (uint32_t)((double)jpegInfo.yDensity / 0.393700787 + 0.5); + } + } + + return HGBASE_ERR_OK; + } + + HGBmpLoadInfo bmpInfo; + ret = HGImgFmt_LoadBmpImage(fileName, &bmpInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK == ret) + { + if (NULL != info) + { + info->width = bmpInfo.width; + info->height = bmpInfo.height; + info->bpp = bmpInfo.bitCount; + info->xDpi = (uint32_t)((double)bmpInfo.xPelsPerMeter / 39.3700787 + 0.5); + info->yDpi = (uint32_t)((double)bmpInfo.yPelsPerMeter / 39.3700787 + 0.5); + } + + return HGBASE_ERR_OK; + } + + HGPngLoadInfo pngInfo; + ret = HGImgFmt_LoadPngImage(fileName, &pngInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK == ret) + { + if (NULL != info) + { + info->width = pngInfo.width; + info->height = pngInfo.height; + info->bpp = pngInfo.pixelDepth; + info->xDpi = 0; + info->yDpi = 0; + if (HGIMGFMT_PNGPHYSUNIT_METER == pngInfo.physUnitType) + { + info->xDpi = (uint32_t)((double)pngInfo.xPixelsPerUnit / 39.3700787 + 0.5); + info->yDpi = (uint32_t)((double)pngInfo.yPixelsPerUnit / 39.3700787 + 0.5); + } + } + + return HGBASE_ERR_OK; + } + + HGTiffLoadInfo tiffInfo; + ret = HGImgFmt_LoadTiffImage(fileName, &tiffInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK == ret) + { + if (NULL != info) + { + info->width = tiffInfo.width; + info->height = tiffInfo.height; + info->bpp = tiffInfo.bitsPerSample * tiffInfo.samplesPerPixel; + info->xDpi = 0; + info->yDpi = 0; + if (HGIMGFMT_TIFFRESUNIT_INCH == tiffInfo.resolutionUnit) + { + info->xDpi = (uint32_t)(tiffInfo.xResolution + 0.5f); + info->yDpi = (uint32_t)(tiffInfo.yResolution + 0.5f); + } + else if (HGIMGFMT_TIFFRESUNIT_CENTIMETER == tiffInfo.resolutionUnit) + { + info->xDpi = (uint32_t)((double)tiffInfo.xResolution / 0.393700787 + 0.5); + info->yDpi = (uint32_t)((double)tiffInfo.yResolution / 0.393700787 + 0.5); + } + } + + return HGBASE_ERR_OK; + } + + HGPdfPageInfo pdfInfo; + ret = HGImgFmt_LoadPdfImage(fileName, &pdfInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK == ret) + { + if (NULL != info) + { + info->width = pdfInfo.width; + info->height = pdfInfo.height; + info->bpp = pdfInfo.bpp; + info->xDpi = 0; + info->yDpi = 0; + } + + return HGBASE_ERR_OK; + } + + HGOfdPageInfo ofdInfo; + ret = HGImgFmt_LoadOfdImage(fileName, &ofdInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK == ret) + { + if (NULL != info) + { + info->width = ofdInfo.width; + info->height = ofdInfo.height; + info->bpp = ofdInfo.bpp; + info->xDpi = 0; + info->yDpi = 0; + } + + return HGBASE_ERR_OK; + } + + HGGifLoadInfo gifInfo; + ret = HGImgFmt_LoadGifImage(fileName, &gifInfo, NULL, imgType, imgOrigin, image); + if (HGBASE_ERR_OK == ret) + { + if (NULL != info) + { + info->width = gifInfo.width; + info->height = gifInfo.height; + info->bpp = gifInfo.colorResolution; + info->xDpi = 0; + info->yDpi = 0; + } + + return HGBASE_ERR_OK; + } + + HGPnmLoadInfo pnmInfo; + ret = HGImgFmt_LoadPnmImage(fileName, &pnmInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK == ret) + { + if (NULL != info) + { + info->width = pnmInfo.width; + info->height = pnmInfo.height; + info->bpp = 1; + if (pnmInfo.type == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmInfo.type == HGIMGFMT_PNMTYPE_GRAY_BINARY) + info->bpp = 8; + else if (pnmInfo.type == HGIMGFMT_PNMTYPE_RGB_ASCII || pnmInfo.type == HGIMGFMT_PNMTYPE_RGB_BINARY) + info->bpp = 24; + info->xDpi = 0; + info->yDpi = 0; + } + + return HGBASE_ERR_OK; + } + + return ret; +} + +HGResult HGAPI HGImgFmt_SaveImage(HGImage image, HGUInt fmtType, const HGImgFmtSaveInfo* info, const HGChar* fileName) +{ + if (fmtType > HGIMGFMT_TYPE_PNM) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == fmtType) + { + HGImgFmt_GetImgFmtTypeFromFileName(fileName, &fmtType); + if (fmtType < HGIMGFMT_TYPE_JPEG || fmtType > HGIMGFMT_TYPE_PNM) + { + return HGBASE_ERR_INVALIDARG; + } + } + + HGUInt xDpi = 96, yDpi = 96; + HGBase_GetImageDpi(image, &xDpi, &yDpi); + + if (HGIMGFMT_TYPE_JPEG == fmtType) + { + HGJpegSaveInfo jpegInfo; + HGJpegSaveInfo* pJpegInfo = NULL; + + if (NULL != info) + { + jpegInfo.quality = info->jpegQuality; + jpegInfo.densityUnit = HGIMGFMT_JPEGDENUNIT_INCH; + jpegInfo.xDensity = xDpi; + jpegInfo.yDensity = yDpi; + pJpegInfo = &jpegInfo; + } + + return HGImgFmt_SaveJpegImage(image, pJpegInfo, fileName); + } + else if (HGIMGFMT_TYPE_BMP == fmtType) + { + HGBmpSaveInfo bmpInfo; + HGBmpSaveInfo* pBmpInfo = NULL; + + if (NULL != info) + { + bmpInfo.xPelsPerMeter = (uint32_t)((double)xDpi * 39.3700787 + 0.5); + bmpInfo.yPelsPerMeter = (uint32_t)((double)yDpi * 39.3700787 + 0.5); + pBmpInfo = &bmpInfo; + } + + return HGImgFmt_SaveBmpImage(image, pBmpInfo, fileName); + } + else if (HGIMGFMT_TYPE_PNG == fmtType) + { + HGPngSaveInfo pngInfo; + HGPngSaveInfo* pPngInfo = NULL; + + if (NULL != info) + { + pngInfo.physUnitType = HGIMGFMT_PNGPHYSUNIT_METER; + pngInfo.xPixelsPerUnit = (uint32_t)((double)xDpi * 39.3700787 + 0.5); + pngInfo.yPixelsPerUnit = (uint32_t)((double)yDpi * 39.3700787 + 0.5); + pPngInfo = &pngInfo; + } + + return HGImgFmt_SavePngImage(image, pPngInfo, fileName); + } + else if (HGIMGFMT_TYPE_TIFF == fmtType) + { + HGTiffSaveInfo tiffInfo; + HGTiffSaveInfo* pTiffInfo = NULL; + + if (NULL != info) + { + tiffInfo.compression = info->tiffCompression; + tiffInfo.jpegQuality = info->tiffJpegQuality; + tiffInfo.resolutionUnit = HGIMGFMT_TIFFRESUNIT_INCH; + tiffInfo.xResolution = (float)xDpi; + tiffInfo.yResolution = (float)yDpi; + pTiffInfo = &tiffInfo; + } + + return HGImgFmt_SaveTiffImage(image, pTiffInfo, fileName); + } + else if (HGIMGFMT_TYPE_PDF == fmtType) + { + HGJpegSaveInfo jpegInfo; + HGJpegSaveInfo* pJpegInfo = NULL; + + if (NULL != info) + { + jpegInfo.quality = info->jpegQuality; + jpegInfo.densityUnit = HGIMGFMT_JPEGDENUNIT_INCH; + jpegInfo.xDensity = xDpi; + jpegInfo.yDensity = yDpi; + pJpegInfo = &jpegInfo; + } + + return HGImgFmt_SavePdfJpegImage(image, pJpegInfo, fileName); + } + else if (HGIMGFMT_TYPE_OFD == fmtType) + { + HGJpegSaveInfo jpegInfo; + HGJpegSaveInfo* pJpegInfo = NULL; + + if (NULL != info) + { + jpegInfo.quality = info->jpegQuality; + jpegInfo.densityUnit = HGIMGFMT_JPEGDENUNIT_INCH; + jpegInfo.xDensity = xDpi; + jpegInfo.yDensity = yDpi; + pJpegInfo = &jpegInfo; + } + + return HGImgFmt_SaveOfdJpegImage(image, pJpegInfo, fileName); + } + else if (HGIMGFMT_TYPE_GIF == fmtType) + { + return HGImgFmt_SaveGifImage(image, NULL, 50, HG_MAKECOLOR(255, 255, 255, 255), fileName); + } + + assert(HGIMGFMT_TYPE_PNM == fmtType); + + return HGImgFmt_SavePnmImage(image, NULL, fileName); +} + +HGResult HGAPI HGImgFmt_OpenImageReader(const HGChar* fileName, HGUInt fmtType, HGImgFmtReader* reader) +{ + if (NULL == fileName || fmtType > HGIMGFMT_TYPE_PNM || NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + if (HGIMGFMT_TYPE_JPEG == fmtType || HGIMGFMT_TYPE_BMP == fmtType + || HGIMGFMT_TYPE_PNG == fmtType || HGIMGFMT_TYPE_PNM == fmtType) + { + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = fmtType; + imgFmtReaderImpl->handle = NULL; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_TIFF == fmtType) + { + HGTiffReader tiffReader = NULL; + HGResult ret = HGImgFmt_OpenTiffReader(fileName, &tiffReader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = fmtType; + imgFmtReaderImpl->handle = tiffReader; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_PDF == fmtType) + { + HGPdfReader pdfReader = NULL; + HGResult ret = HGImgFmt_OpenPdfReader(fileName, &pdfReader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = fmtType; + imgFmtReaderImpl->handle = pdfReader; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_OFD == fmtType) + { + HGOfdReader ofdReader = NULL; + HGResult ret = HGImgFmt_OpenOfdReader(fileName, &ofdReader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = fmtType; + imgFmtReaderImpl->handle = ofdReader; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_GIF == fmtType) + { + HGGifLoadInfo gifLoadInfo; + HGGifReader gifReader = NULL; + HGResult ret = HGImgFmt_OpenGifReader(fileName, &gifLoadInfo, &gifReader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = fmtType; + imgFmtReaderImpl->handle = gifReader; + memcpy(&imgFmtReaderImpl->gifLoadInfo, &gifLoadInfo, sizeof(HGGifLoadInfo)); + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + + assert(0 == fmtType); + + HGBool isJpeg = HGFALSE; + HGResult ret = HGImgFmt_CheckJpegFile(fileName, &isJpeg); + if (isJpeg) + { + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = HGIMGFMT_TYPE_JPEG; + imgFmtReaderImpl->handle = NULL; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + + HGBool isBmp = HGFALSE; + ret = HGImgFmt_CheckBmpFile(fileName, &isBmp); + if (isBmp) + { + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = HGIMGFMT_TYPE_BMP; + imgFmtReaderImpl->handle = NULL; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + + HGBool isPng = HGFALSE; + ret = HGImgFmt_CheckPngFile(fileName, &isPng); + if (isPng) + { + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = HGIMGFMT_TYPE_PNG; + imgFmtReaderImpl->handle = NULL; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + + HGTiffReader tiffReader = NULL; + ret = HGImgFmt_OpenTiffReader(fileName, &tiffReader); + if (HGBASE_ERR_OK == ret) + { + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = HGIMGFMT_TYPE_TIFF; + imgFmtReaderImpl->handle = tiffReader; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + + HGPdfReader pdfReader = NULL; + ret = HGImgFmt_OpenPdfReader(fileName, &pdfReader); + if (HGBASE_ERR_OK == ret) + { + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = HGIMGFMT_TYPE_PDF; + imgFmtReaderImpl->handle = pdfReader; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + + HGOfdReader ofdReader = NULL; + ret = HGImgFmt_OpenOfdReader(fileName, &ofdReader); + if (HGBASE_ERR_OK == ret) + { + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = HGIMGFMT_TYPE_OFD; + imgFmtReaderImpl->handle = ofdReader; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + + HGGifLoadInfo gifLoadInfo; + HGGifReader gifReader = NULL; + ret = HGImgFmt_OpenGifReader(fileName, &gifLoadInfo, &gifReader); + if (HGBASE_ERR_OK == ret) + { + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = HGIMGFMT_TYPE_GIF; + imgFmtReaderImpl->handle = gifReader; + memcpy(&imgFmtReaderImpl->gifLoadInfo, &gifLoadInfo, sizeof(HGGifLoadInfo)); + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + + HGBool isPnm = HGFALSE; + ret = HGImgFmt_CheckPnmFile(fileName, &isPnm); + if (isPnm) + { + HGImgFmtReaderImpl* imgFmtReaderImpl = new HGImgFmtReaderImpl; + imgFmtReaderImpl->fileName = fileName; + imgFmtReaderImpl->fmtType = HGIMGFMT_TYPE_PNM; + imgFmtReaderImpl->handle = NULL; + *reader = (HGImgFmtReader)imgFmtReaderImpl; + return HGBASE_ERR_OK; + } + + return ret; +} + +HGResult HGAPI HGImgFmt_CloseImageReader(HGImgFmtReader reader) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImgFmtReaderImpl* imgFmtReaderImpl = (HGImgFmtReaderImpl*)reader; + if (HGIMGFMT_TYPE_TIFF == imgFmtReaderImpl->fmtType) + HGImgFmt_CloseTiffReader((HGTiffReader)imgFmtReaderImpl->handle); + else if (HGIMGFMT_TYPE_PDF == imgFmtReaderImpl->fmtType) + HGImgFmt_ClosePdfReader((HGPdfReader)imgFmtReaderImpl->handle); + else if (HGIMGFMT_TYPE_OFD == imgFmtReaderImpl->fmtType) + HGImgFmt_CloseOfdReader((HGOfdReader)imgFmtReaderImpl->handle); + else if (HGIMGFMT_TYPE_GIF == imgFmtReaderImpl->fmtType) + HGImgFmt_CloseGifReader((HGGifReader)imgFmtReaderImpl->handle); + + delete imgFmtReaderImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_GetImagePageCount(HGImgFmtReader reader, HGUInt* count) +{ + if (NULL == reader || NULL == count) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImgFmtReaderImpl* imgFmtReaderImpl = (HGImgFmtReaderImpl*)reader; + if (HGIMGFMT_TYPE_TIFF == imgFmtReaderImpl->fmtType) + return HGImgFmt_GetTiffPageCount((HGTiffReader)imgFmtReaderImpl->handle, count); + else if (HGIMGFMT_TYPE_PDF == imgFmtReaderImpl->fmtType) + return HGImgFmt_GetPdfPageCount((HGPdfReader)imgFmtReaderImpl->handle, count); + else if (HGIMGFMT_TYPE_OFD == imgFmtReaderImpl->fmtType) + return HGImgFmt_GetOfdPageCount((HGOfdReader)imgFmtReaderImpl->handle, count); + else if (HGIMGFMT_TYPE_GIF == imgFmtReaderImpl->fmtType) + { + *count = imgFmtReaderImpl->gifLoadInfo.imageCount; + return HGBASE_ERR_OK; + } + + *count = 1; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_LoadImageFromReader(HGImgFmtReader reader, HGUInt index, HGImgFmtLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImgFmtReaderImpl* imgFmtReaderImpl = (HGImgFmtReaderImpl*)reader; + if (HGIMGFMT_TYPE_JPEG == imgFmtReaderImpl->fmtType) + { + if (0 != index) + { + return HGBASE_ERR_INVALIDARG; + } + + HGJpegLoadInfo jpegInfo; + HGResult ret = HGImgFmt_LoadJpegImage(imgFmtReaderImpl->fileName.c_str(), &jpegInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = jpegInfo.width; + info->height = jpegInfo.height; + info->bpp = jpegInfo.numComponents * 8; + info->xDpi = 0; + info->yDpi = 0; + if (HGIMGFMT_JPEGDENUNIT_INCH == jpegInfo.densityUnit) + { + info->xDpi = jpegInfo.xDensity; + info->yDpi = jpegInfo.yDensity; + } + else if (HGIMGFMT_JPEGDENUNIT_CENTIMETER == jpegInfo.densityUnit) + { + info->xDpi = (uint32_t)((double)jpegInfo.xDensity / 0.393700787 + 0.5); + info->yDpi = (uint32_t)((double)jpegInfo.yDensity / 0.393700787 + 0.5); + } + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_BMP == imgFmtReaderImpl->fmtType) + { + if (0 != index) + { + return HGBASE_ERR_INVALIDARG; + } + + HGBmpLoadInfo bmpInfo; + HGResult ret = HGImgFmt_LoadBmpImage(imgFmtReaderImpl->fileName.c_str(), &bmpInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = bmpInfo.width; + info->height = bmpInfo.height; + info->bpp = bmpInfo.bitCount; + info->xDpi = (uint32_t)((double)bmpInfo.xPelsPerMeter / 39.3700787 + 0.5); + info->yDpi = (uint32_t)((double)bmpInfo.yPelsPerMeter / 39.3700787 + 0.5); + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_PNG == imgFmtReaderImpl->fmtType) + { + if (0 != index) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPngLoadInfo pngInfo; + HGResult ret = HGImgFmt_LoadPngImage(imgFmtReaderImpl->fileName.c_str(), &pngInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = pngInfo.width; + info->height = pngInfo.height; + info->bpp = pngInfo.pixelDepth; + info->xDpi = 0; + info->yDpi = 0; + if (HGIMGFMT_PNGPHYSUNIT_METER == pngInfo.physUnitType) + { + info->xDpi = (uint32_t)((double)pngInfo.xPixelsPerUnit / 39.3700787 + 0.5); + info->yDpi = (uint32_t)((double)pngInfo.yPixelsPerUnit / 39.3700787 + 0.5); + } + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_TIFF == imgFmtReaderImpl->fmtType) + { + HGTiffLoadInfo tiffInfo; + HGResult ret = HGImgFmt_LoadImageFromTiffReader((HGTiffReader)imgFmtReaderImpl->handle, index, &tiffInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = tiffInfo.width; + info->height = tiffInfo.height; + info->bpp = tiffInfo.bitsPerSample * tiffInfo.samplesPerPixel; + info->xDpi = 0; + info->yDpi = 0; + if (HGIMGFMT_TIFFRESUNIT_INCH == tiffInfo.resolutionUnit) + { + info->xDpi = (uint32_t)(tiffInfo.xResolution + 0.5f); + info->yDpi = (uint32_t)(tiffInfo.yResolution + 0.5f); + } + else if (HGIMGFMT_TIFFRESUNIT_CENTIMETER == tiffInfo.resolutionUnit) + { + info->xDpi = (uint32_t)((double)tiffInfo.xResolution / 0.393700787 + 0.5); + info->yDpi = (uint32_t)((double)tiffInfo.yResolution / 0.393700787 + 0.5); + } + } + + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_PDF == imgFmtReaderImpl->fmtType) + { + HGResult ret = HGBASE_ERR_OK; + if (NULL != info) + { + info->width = 0; + info->height = 0; + info->bpp = 0; + info->xDpi = 0; + info->yDpi = 0; + + HGPdfPageInfo pdfInfo; + ret = HGImgFmt_GetPdfPageInfo((HGPdfReader)imgFmtReaderImpl->handle, index, &pdfInfo); + if (HGBASE_ERR_OK == ret) + { + info->width = pdfInfo.width; + info->height = pdfInfo.height; + info->bpp = pdfInfo.bpp; + } + } + + if (ret == HGBASE_ERR_OK && NULL != image) + { + ret = HGImgFmt_LoadImageFromPdfReader((HGPdfReader)imgFmtReaderImpl->handle, index, 1.0f, 1.0f, imgType, imgOrigin, image); + } + + return ret; + } + else if (HGIMGFMT_TYPE_OFD == imgFmtReaderImpl->fmtType) + { + HGResult ret = HGBASE_ERR_OK; + if (NULL != info) + { + info->width = 0; + info->height = 0; + info->bpp = 0; + info->xDpi = 0; + info->yDpi = 0; + + HGOfdPageInfo ofdInfo; + ret = HGImgFmt_GetOfdPageInfo((HGOfdReader)imgFmtReaderImpl->handle, index, &ofdInfo); + if (HGBASE_ERR_OK == ret) + { + info->width = ofdInfo.width; + info->height = ofdInfo.height; + info->bpp = ofdInfo.bpp; + } + } + + if (ret == HGBASE_ERR_OK && NULL != image) + { + ret = HGImgFmt_LoadImageFromOfdReader((HGOfdReader)imgFmtReaderImpl->handle, index, 1.0f, 1.0f, imgType, imgOrigin, image); + } + + return ret; + } + else if (HGIMGFMT_TYPE_PNM == imgFmtReaderImpl->fmtType) + { + if (0 != index) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPnmLoadInfo pnmInfo; + HGResult ret = HGImgFmt_LoadPnmImage(imgFmtReaderImpl->fileName.c_str(), &pnmInfo, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (NULL != info) + { + info->width = pnmInfo.width; + info->height = pnmInfo.height; + info->bpp = 1; + if (pnmInfo.type == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmInfo.type == HGIMGFMT_PNMTYPE_GRAY_BINARY) + info->bpp = 8; + else if (pnmInfo.type == HGIMGFMT_PNMTYPE_RGB_ASCII || pnmInfo.type == HGIMGFMT_PNMTYPE_RGB_BINARY) + info->bpp = 24; + info->xDpi = 0; + info->yDpi = 0; + } + + return HGBASE_ERR_OK; + } + + assert(HGIMGFMT_TYPE_GIF == imgFmtReaderImpl->fmtType); + + if (NULL == image) + { + if (0 != imgType || 0 != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + + if (index >= imgFmtReaderImpl->gifLoadInfo.imageCount) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL != info) + { + info->width = imgFmtReaderImpl->gifLoadInfo.width; + info->height = imgFmtReaderImpl->gifLoadInfo.height; + info->bpp = imgFmtReaderImpl->gifLoadInfo.colorResolution; + info->xDpi = 0; + info->yDpi = 0; + } + + if (NULL != image) + { + HGResult ret = HGImgFmt_LoadImageFromGifReader((HGGifReader)imgFmtReaderImpl->handle, index, NULL, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_OpenImageWriter(const HGChar* fileName, HGUInt fmtType, HGImgFmtWriter* writer) +{ + if (fmtType > HGIMGFMT_TYPE_PNM || NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == fmtType) + { + HGImgFmt_GetImgFmtTypeFromFileName(fileName, &fmtType); + if (fmtType < HGIMGFMT_TYPE_JPEG || fmtType > HGIMGFMT_TYPE_PNM) + { + return HGBASE_ERR_INVALIDARG; + } + } + + if (HGIMGFMT_TYPE_JPEG == fmtType || HGIMGFMT_TYPE_BMP == fmtType + || HGIMGFMT_TYPE_PNG == fmtType || HGIMGFMT_TYPE_PNM == fmtType) + { + HGImgFmtWriterImpl* imgFmtWriterImpl = new HGImgFmtWriterImpl; + imgFmtWriterImpl->fileName = fileName; + imgFmtWriterImpl->fmtType = fmtType; + imgFmtWriterImpl->handle = NULL; + imgFmtWriterImpl->write = HGFALSE; + *writer = (HGImgFmtWriter)imgFmtWriterImpl; + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_TIFF == fmtType) + { + HGTiffWriter tiffWriter = NULL; + HGResult ret = HGImgFmt_OpenTiffWriter(fileName, &tiffWriter); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HGImgFmtWriterImpl* imgFmtWriterImpl = new HGImgFmtWriterImpl; + imgFmtWriterImpl->fileName = fileName; + imgFmtWriterImpl->fmtType = fmtType; + imgFmtWriterImpl->handle = tiffWriter; + imgFmtWriterImpl->write = HGFALSE; + *writer = (HGImgFmtWriter)imgFmtWriterImpl; + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_PDF == fmtType) + { + HGPdfImageWriter pdfWriter = NULL; + HGResult ret = HGImgFmt_OpenPdfImageWriter(fileName, &pdfWriter); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HGImgFmtWriterImpl* imgFmtWriterImpl = new HGImgFmtWriterImpl; + imgFmtWriterImpl->fileName = fileName; + imgFmtWriterImpl->fmtType = fmtType; + imgFmtWriterImpl->handle = pdfWriter; + imgFmtWriterImpl->write = HGFALSE; + *writer = (HGImgFmtWriter)imgFmtWriterImpl; + return HGBASE_ERR_OK; + } + else if (HGIMGFMT_TYPE_OFD == fmtType) + { + HGOfdImageWriter ofdWriter = NULL; + HGResult ret = HGImgFmt_OpenOfdImageWriter(fileName, &ofdWriter); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HGImgFmtWriterImpl* imgFmtWriterImpl = new HGImgFmtWriterImpl; + imgFmtWriterImpl->fileName = fileName; + imgFmtWriterImpl->fmtType = fmtType; + imgFmtWriterImpl->handle = ofdWriter; + imgFmtWriterImpl->write = HGFALSE; + *writer = (HGImgFmtWriter)imgFmtWriterImpl; + return HGBASE_ERR_OK; + } + + assert(HGIMGFMT_TYPE_GIF == fmtType); + + HGGifWriter gifWriter = NULL; + HGResult ret = HGImgFmt_OpenGifWriter(fileName, NULL, &gifWriter); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HGImgFmtWriterImpl* imgFmtWriterImpl = new HGImgFmtWriterImpl; + imgFmtWriterImpl->fileName = fileName; + imgFmtWriterImpl->fmtType = fmtType; + imgFmtWriterImpl->handle = gifWriter; + imgFmtWriterImpl->write = HGFALSE; + *writer = (HGImgFmtWriter)imgFmtWriterImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_CloseImageWriter(HGImgFmtWriter writer) +{ + if (NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImgFmtWriterImpl* imgFmtWriterImpl = (HGImgFmtWriterImpl*)writer; + if (HGIMGFMT_TYPE_TIFF == imgFmtWriterImpl->fmtType) + HGImgFmt_CloseTiffWriter((HGTiffWriter)imgFmtWriterImpl->handle); + else if (HGIMGFMT_TYPE_PDF == imgFmtWriterImpl->fmtType) + HGImgFmt_ClosePdfImageWriter((HGPdfImageWriter)imgFmtWriterImpl->handle); + else if (HGIMGFMT_TYPE_OFD == imgFmtWriterImpl->fmtType) + HGImgFmt_CloseOfdImageWriter((HGOfdImageWriter)imgFmtWriterImpl->handle); + else if (HGIMGFMT_TYPE_GIF == imgFmtWriterImpl->fmtType) + HGImgFmt_CloseGifWriter((HGGifWriter)imgFmtWriterImpl->handle); + + delete imgFmtWriterImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveImageToWriter(HGImgFmtWriter writer, HGImage image, const HGImgFmtSaveInfo* info) +{ + if (NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGUInt xDpi = 96, yDpi = 96; + HGBase_GetImageDpi(image, &xDpi, &yDpi); + + HGImgFmtWriterImpl* imgFmtWriterImpl = (HGImgFmtWriterImpl*)writer; + if (HGIMGFMT_TYPE_JPEG == imgFmtWriterImpl->fmtType) + { + if (imgFmtWriterImpl->write) + { + return HGBASE_ERR_FAIL; + } + + HGJpegSaveInfo jpegInfo; + HGJpegSaveInfo* pJpegInfo = NULL; + + if (NULL != info) + { + jpegInfo.quality = info->jpegQuality; + jpegInfo.densityUnit = HGIMGFMT_JPEGDENUNIT_INCH; + jpegInfo.xDensity = xDpi; + jpegInfo.yDensity = yDpi; + pJpegInfo = &jpegInfo; + } + + HGResult ret = HGImgFmt_SaveJpegImage(image, pJpegInfo, imgFmtWriterImpl->fileName.c_str()); + if (HGBASE_ERR_OK == ret) + { + imgFmtWriterImpl->write = HGTRUE; + } + + return ret; + } + else if (HGIMGFMT_TYPE_BMP == imgFmtWriterImpl->fmtType) + { + if (imgFmtWriterImpl->write) + { + return HGBASE_ERR_FAIL; + } + + HGBmpSaveInfo bmpInfo; + HGBmpSaveInfo* pBmpInfo = NULL; + + if (NULL != info) + { + bmpInfo.xPelsPerMeter = (uint32_t)((double)xDpi * 39.3700787 + 0.5); + bmpInfo.yPelsPerMeter = (uint32_t)((double)yDpi * 39.3700787 + 0.5); + pBmpInfo = &bmpInfo; + } + + HGResult ret = HGImgFmt_SaveBmpImage(image, pBmpInfo, imgFmtWriterImpl->fileName.c_str()); + if (HGBASE_ERR_OK == ret) + { + imgFmtWriterImpl->write = HGTRUE; + } + + return ret; + } + else if (HGIMGFMT_TYPE_PNG == imgFmtWriterImpl->fmtType) + { + if (imgFmtWriterImpl->write) + { + return HGBASE_ERR_FAIL; + } + + HGPngSaveInfo pngInfo; + HGPngSaveInfo* pPngInfo = NULL; + + if (NULL != info) + { + pngInfo.physUnitType = HGIMGFMT_PNGPHYSUNIT_METER; + pngInfo.xPixelsPerUnit = (uint32_t)((double)xDpi * 39.3700787 + 0.5); + pngInfo.yPixelsPerUnit = (uint32_t)((double)yDpi * 39.3700787 + 0.5); + pPngInfo = &pngInfo; + } + + HGResult ret = HGImgFmt_SavePngImage(image, pPngInfo, imgFmtWriterImpl->fileName.c_str()); + if (HGBASE_ERR_OK == ret) + { + imgFmtWriterImpl->write = HGTRUE; + } + + return ret; + } + else if (HGIMGFMT_TYPE_TIFF == imgFmtWriterImpl->fmtType) + { + HGTiffSaveInfo tiffInfo; + HGTiffSaveInfo* pTiffInfo = NULL; + + if (NULL != info) + { + tiffInfo.compression = info->tiffCompression; + tiffInfo.jpegQuality = info->tiffJpegQuality; + tiffInfo.resolutionUnit = HGIMGFMT_TIFFRESUNIT_INCH; + tiffInfo.xResolution = (float)xDpi; + tiffInfo.yResolution = (float)yDpi; + pTiffInfo = &tiffInfo; + } + + return HGImgFmt_SaveImageToTiffWriter((HGTiffWriter)imgFmtWriterImpl->handle, image, pTiffInfo); + } + else if (HGIMGFMT_TYPE_PDF == imgFmtWriterImpl->fmtType) + { + HGJpegSaveInfo jpegInfo; + HGJpegSaveInfo* pJpegInfo = NULL; + + if (NULL != info) + { + jpegInfo.quality = info->jpegQuality; + jpegInfo.densityUnit = HGIMGFMT_JPEGDENUNIT_INCH; + jpegInfo.xDensity = xDpi; + jpegInfo.yDensity = yDpi; + pJpegInfo = &jpegInfo; + } + + return HGImgFmt_SaveJpegImageToPdfImageWriter((HGPdfImageWriter)imgFmtWriterImpl->handle, image, pJpegInfo); + } + else if (HGIMGFMT_TYPE_OFD == imgFmtWriterImpl->fmtType) + { + HGJpegSaveInfo jpegInfo; + HGJpegSaveInfo* pJpegInfo = NULL; + + if (NULL != info) + { + jpegInfo.quality = info->jpegQuality; + jpegInfo.densityUnit = HGIMGFMT_JPEGDENUNIT_INCH; + jpegInfo.xDensity = xDpi; + jpegInfo.yDensity = yDpi; + pJpegInfo = &jpegInfo; + } + + return HGImgFmt_SaveJpegImageToOfdImageWriter((HGOfdImageWriter)imgFmtWriterImpl->handle, image, pJpegInfo); + } + else if (HGIMGFMT_TYPE_PNM == imgFmtWriterImpl->fmtType) + { + if (imgFmtWriterImpl->write) + { + return HGBASE_ERR_FAIL; + } + + HGResult ret = HGImgFmt_SavePnmImage(image, NULL, imgFmtWriterImpl->fileName.c_str()); + if (HGBASE_ERR_OK == ret) + { + imgFmtWriterImpl->write = HGTRUE; + } + + return ret; + } + + assert(HGIMGFMT_TYPE_GIF == imgFmtWriterImpl->fmtType); + + return HGImgFmt_SaveImageToGifWriter((HGGifWriter)imgFmtWriterImpl->handle, 50, HG_MAKECOLOR(255, 255, 255, 255), image); +} \ No newline at end of file diff --git a/app/modules/imgfmt/HGImgFmt.h b/app/modules/imgfmt/HGImgFmt.h new file mode 100644 index 0000000..133b848 --- /dev/null +++ b/app/modules/imgfmt/HGImgFmt.h @@ -0,0 +1,77 @@ +#ifndef __HGIMGFMT_H__ +#define __HGIMGFMT_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" +#include "HGTiff.h" + +HG_DECLARE_HANDLE(HGImgFmtReader); +HG_DECLARE_HANDLE(HGImgFmtWriter); + +/* JPEG */ +#define HGIMGFMT_TYPE_JPEG 1L +/* BMP */ +#define HGIMGFMT_TYPE_BMP 2L +/* PNG */ +#define HGIMGFMT_TYPE_PNG 3L +/* TIFF */ +#define HGIMGFMT_TYPE_TIFF 4L +/* PDF */ +#define HGIMGFMT_TYPE_PDF 5L +/* OFD */ +#define HGIMGFMT_TYPE_OFD 6L +/* GIF */ +#define HGIMGFMT_TYPE_GIF 7L +/* PNM */ +#define HGIMGFMT_TYPE_PNM 8L + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUInt bpp; /* 每像素比特数 */ + HGUInt xDpi; /* x-DPI */ + HGUInt yDpi; /* y-DPI */ +}HGImgFmtLoadInfo; + +typedef struct +{ + HGUInt jpegQuality; /* jpeg质量 */ + HGUInt tiffCompression; /* tiff压缩方式, 见HGIMGFMT_TIFFCOMP_* */ + HGUInt tiffJpegQuality; /* tiff-jpeg质量 */ +}HGImgFmtSaveInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_GetImgFmtType(const HGChar* fileName, HGUInt* fmtType); + +HGEXPORT HGResult HGAPI HGImgFmt_GetImgFmtTypeFromFileName(const HGChar* fileName, HGUInt* fmtType); + +HGEXPORT HGResult HGAPI HGImgFmt_IsMultiImgFmtType(HGUInt fmtType, HGBool *isMulti); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImage(const HGChar *fileName, HGUInt fmtType, HGImgFmtLoadInfo *info, + HGUInt imgType, HGUInt imgOrigin, HGImage *image); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveImage(HGImage image, HGUInt fmtType, const HGImgFmtSaveInfo *info, const HGChar *fileName); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenImageReader(const HGChar *fileName, HGUInt fmtType, HGImgFmtReader *reader); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseImageReader(HGImgFmtReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_GetImagePageCount(HGImgFmtReader reader, HGUInt *count); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromReader(HGImgFmtReader reader, HGUInt index, HGImgFmtLoadInfo *info, + HGUInt imgType, HGUInt imgOrigin, HGImage *image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenImageWriter(const HGChar *fileName, HGUInt fmtType, HGImgFmtWriter *writer); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseImageWriter(HGImgFmtWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveImageToWriter(HGImgFmtWriter writer, HGImage image, const HGImgFmtSaveInfo *info); + +#endif /* __HGIMGFMT_H__ */ \ No newline at end of file diff --git a/app/modules/imgfmt/HGImgFmtErr.h b/app/modules/imgfmt/HGImgFmtErr.h new file mode 100644 index 0000000..c334856 --- /dev/null +++ b/app/modules/imgfmt/HGImgFmtErr.h @@ -0,0 +1,7 @@ +#ifndef __HGIMGFMTERR_H__ +#define __HGIMGFMTERR_H__ + +/* 一般错误 */ +#define HGIMGFMT_ERR_FAIL 0x00002001L + +#endif /* __HGIMGFMTERR_H__ */ \ No newline at end of file diff --git a/app/modules/imgfmt/HGJpeg.cpp b/app/modules/imgfmt/HGJpeg.cpp new file mode 100644 index 0000000..61e7194 --- /dev/null +++ b/app/modules/imgfmt/HGJpeg.cpp @@ -0,0 +1,538 @@ +#include "HGJpeg.h" +#include "../base/HGInc.h" +#include "../base/HGInfo.h" +extern "C" +{ +#include "jpeglib.h" +#include "jmemsys.h" +}; + +struct my_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; + +METHODDEF(void) my_error_exit(j_common_ptr cinfo) +{ + my_error_mgr* myerr = (my_error_mgr*)cinfo->err; + (*cinfo->err->output_message)(cinfo); + longjmp(myerr->setjmp_buffer, (int)HGIMGFMT_ERR_FAIL); +} + +HGResult HGAPI HGImgFmt_CheckJpegFile(const HGChar* fileName, HGBool* isJpeg) +{ + if (NULL == fileName || NULL == isJpeg) + { + return HGBASE_ERR_INVALIDARG; + } + + HGJpegLoadInfo info; + HGResult ret = HGImgFmt_LoadJpegImage(fileName, &info, 0, 0, NULL); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + *isJpeg = HGTRUE; + return ret; +} + +HGResult HGAPI HGImgFmt_LoadJpegImage(const HGChar* fileName, HGJpegLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL == image) + { + if (0 != imgType || 0 != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + else + { + if (0 != imgType && HGBASE_IMGTYPE_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType + && HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType + && HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + +#if defined(HG_CMP_MSC) + if (0 != _access(fileName, 0)) +#else + if (0 != access(fileName, 0)) +#endif + { + return HGBASE_ERR_FILENOTEXIST; + } + + FILE* file = fopen(fileName, "rb"); + if (NULL == file) + { + return HGBASE_ERR_ACCESSDENIED; + } + + struct jpeg_decompress_struct cinfo; + struct my_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + + HGImage image2 = NULL; + + int jmpResult = setjmp(jerr.setjmp_buffer); + if (0 != jmpResult) + { + HGBase_DestroyImage(image2); + image2 = NULL; + jpeg_destroy_decompress(&cinfo); + fclose(file); + file = NULL; + return (HGResult)jmpResult; + } + + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, file); + jpeg_read_header(&cinfo, TRUE); + + if (NULL != info) + { + info->width = cinfo.image_width; + info->height = cinfo.image_height; + info->numComponents = cinfo.num_components; + info->colorSpace = cinfo.jpeg_color_space; + info->densityUnit = cinfo.density_unit; + info->xDensity = cinfo.X_density; + info->yDensity = cinfo.Y_density; + } + + if (NULL != image) + { + if (0 == imgType) + { + if (JCS_GRAYSCALE != cinfo.out_color_space) + imgType = HGBASE_IMGTYPE_RGB; + else + imgType = HGBASE_IMGTYPE_GRAY; + } + + if (0 == imgOrigin) + { + imgOrigin = HGBASE_IMGORIGIN_TOP; + } + + cinfo.out_color_space = JCS_RGB; + jpeg_start_decompress(&cinfo); + + HGResult ret = HGBase_CreateImage(cinfo.output_width, cinfo.output_height, + HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + longjmp(jerr.setjmp_buffer, (int)ret); + } + + if (1 == cinfo.density_unit) + { + HGBase_SetImageDpi(image2, cinfo.X_density, cinfo.Y_density); + } + else if (2 == cinfo.density_unit) + { + uint32_t xDpi = (uint32_t)(cinfo.X_density / 0.393700787402 + 0.5); + uint32_t yDpi = (uint32_t)(cinfo.Y_density / 0.393700787402 + 0.5); + HGBase_SetImageDpi(image2, xDpi, yDpi); + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image2, &imgInfo); + uint8_t* data; + HGBase_GetImageData(image2, &data); + + while (cinfo.output_scanline < cinfo.output_height) + { + JSAMPROW pEx = data + (HGSize)cinfo.output_scanline * (HGSize)imgInfo.widthStep; + jpeg_read_scanlines(&cinfo, &pEx, 1); + } + + jpeg_finish_decompress(&cinfo); + + ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + longjmp(jerr.setjmp_buffer, (int)ret); + } + } + + HGBase_DestroyImage(image2); + image2 = NULL; + jpeg_destroy_decompress(&cinfo); + fclose(file); + file = NULL; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_LoadJpegImageFromBuffer(HGBuffer buffer, HGJpegLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == buffer) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL == image) + { + if (0 != imgType || 0 != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + else + { + if (0 != imgType && HGBASE_IMGTYPE_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType + && HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType + && HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + + struct jpeg_decompress_struct cinfo; + struct my_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + + HGImage image2 = NULL; + + int jmpResult = setjmp(jerr.setjmp_buffer); + if (0 != jmpResult) + { + HGBase_DestroyImage(image2); + image2 = NULL; + jpeg_destroy_decompress(&cinfo); + return (HGResult)jmpResult; + } + + HGByte* memAddr = NULL; + HGBase_GetBufferData(buffer, &memAddr); + HGUSize size = 0; + HGBase_GetBufferSize(buffer, &size); + + jpeg_create_decompress(&cinfo); + jpeg_mem_src(&cinfo, memAddr, (unsigned long)size); + jpeg_read_header(&cinfo, TRUE); + + if (NULL != info) + { + info->width = cinfo.image_width; + info->height = cinfo.image_height; + info->numComponents = cinfo.num_components; + info->colorSpace = cinfo.jpeg_color_space; + info->densityUnit = cinfo.density_unit; + info->xDensity = cinfo.X_density; + info->yDensity = cinfo.Y_density; + } + + if (NULL != image) + { + if (0 == imgType) + { + if (JCS_GRAYSCALE != cinfo.out_color_space) + imgType = HGBASE_IMGTYPE_RGB; + else + imgType = HGBASE_IMGTYPE_GRAY; + } + + if (0 == imgOrigin) + { + imgOrigin = HGBASE_IMGORIGIN_TOP; + } + + cinfo.out_color_space = JCS_RGB; + jpeg_start_decompress(&cinfo); + + HGResult ret = HGBase_CreateImage(cinfo.output_width, cinfo.output_height, + HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + longjmp(jerr.setjmp_buffer, (int)ret); + } + + if (1 == cinfo.density_unit) + { + HGBase_SetImageDpi(image2, cinfo.X_density, cinfo.Y_density); + } + else if (2 == cinfo.density_unit) + { + uint32_t xDpi = (uint32_t)(cinfo.X_density / 0.393700787402 + 0.5); + uint32_t yDpi = (uint32_t)(cinfo.Y_density / 0.393700787402 + 0.5); + HGBase_SetImageDpi(image2, xDpi, yDpi); + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image2, &imgInfo); + uint8_t* data; + HGBase_GetImageData(image2, &data); + + while (cinfo.output_scanline < cinfo.output_height) + { + JSAMPROW pEx = data + (HGSize)cinfo.output_scanline * (HGSize)imgInfo.widthStep; + jpeg_read_scanlines(&cinfo, &pEx, 1); + } + + jpeg_finish_decompress(&cinfo); + + ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + longjmp(jerr.setjmp_buffer, (int)ret); + } + } + + HGBase_DestroyImage(image2); + image2 = NULL; + jpeg_destroy_decompress(&cinfo); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveJpegImage(HGImage image, const HGJpegSaveInfo* info, const HGChar* fileName) +{ + if (NULL == image || NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL != info) + { + // 判断info参数的合法性 + } + + FILE* file = fopen(fileName, "wb"); + if (NULL == file) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGImgFmt_SaveJpegImage: fopen fail, %s errno=%d", fileName, errno); + return HGBASE_ERR_ACCESSDENIED; + } + + struct jpeg_compress_struct cinfo; + struct my_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + + HGImage image2 = NULL; + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + + int jmpResult = setjmp(jerr.setjmp_buffer); + if (0 != jmpResult) + { + HGBase_SetImageROI(image, &roi); + HGBase_DestroyImage(image2); + image2 = NULL; + jpeg_destroy_compress(&cinfo); + fclose(file); + file = NULL; + return (HGResult)jmpResult; + } + + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, file); + + HGBase_ResetImageROI(image); + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_GRAY == imgInfo.type || HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + longjmp(jerr.setjmp_buffer, (int)ret); + } + else + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + longjmp(jerr.setjmp_buffer, (int)ret); + } + + HGBase_GetImageInfo(image2, &imgInfo); + uint32_t width = imgInfo.width; + uint32_t height = imgInfo.height; + uint32_t type = imgInfo.type; + uint32_t widthStep = imgInfo.widthStep; + uint8_t* data; + HGBase_GetImageData(image2, &data); + + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = (HGBASE_IMGTYPE_GRAY != type) ? 3 : 1; + cinfo.in_color_space = (HGBASE_IMGTYPE_GRAY != type) ? JCS_RGB : JCS_GRAYSCALE; + jpeg_set_defaults(&cinfo); + + int quality; + if (NULL != info) + { + quality = info->quality; + cinfo.density_unit = info->densityUnit; + cinfo.X_density = info->xDensity; + cinfo.Y_density = info->yDensity; + } + else + { + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(image2, &xDpi, &yDpi); + quality = 80; + cinfo.density_unit = 1; + cinfo.X_density = xDpi; + cinfo.Y_density = yDpi; + } + + jpeg_set_quality(&cinfo, (int)quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + while (cinfo.next_scanline < cinfo.image_height) + { + uint8_t* pEx = data + (HGSize)cinfo.next_scanline * (HGSize)imgInfo.widthStep; + jpeg_write_scanlines(&cinfo, &pEx, 1); + } + + jpeg_finish_compress(&cinfo); + + HGBase_SetImageROI(image, &roi); + HGBase_DestroyImage(image2); + image2 = NULL; + jpeg_destroy_compress(&cinfo); + fclose(file); + file = NULL; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveJpegImageToBuffer(HGImage image, const HGJpegSaveInfo* info, HGBuffer* buffer) +{ + if (NULL == image || NULL == buffer) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL != info) + { + // 判断info参数的合法性 + } + + unsigned char* outbuffer = NULL; + size_t outSize = 0; + + struct jpeg_compress_struct cinfo; + struct my_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + + HGImage image2 = NULL; + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + + int jmpResult = setjmp(jerr.setjmp_buffer); + if (0 != jmpResult) + { + HGBase_SetImageROI(image, &roi); + HGBase_DestroyImage(image2); + image2 = NULL; + jpeg_destroy_compress(&cinfo); + // 只有libjpeg为静态库的时候,才能用free + // 否则应该使用jpeg_free_large(NULL, outbuffer, 0); + jpeg_free_large(NULL, outbuffer, 0); + return (HGResult)jmpResult; + } + + jpeg_create_compress(&cinfo); + jpeg_mem_dest(&cinfo, &outbuffer, &outSize); + + HGBase_ResetImageROI(image); + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_GRAY == imgInfo.type || HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + longjmp(jerr.setjmp_buffer, (int)ret); + } + else + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + longjmp(jerr.setjmp_buffer, (int)ret); + } + + HGBase_GetImageInfo(image2, &imgInfo); + uint32_t width = imgInfo.width; + uint32_t height = imgInfo.height; + uint32_t type = imgInfo.type; + uint32_t widthStep = imgInfo.widthStep; + uint8_t* data; + HGBase_GetImageData(image2, &data); + + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = (HGBASE_IMGTYPE_GRAY != type) ? 3 : 1; + cinfo.in_color_space = (HGBASE_IMGTYPE_GRAY != type) ? JCS_RGB : JCS_GRAYSCALE; + jpeg_set_defaults(&cinfo); + + int quality; + if (NULL != info) + { + quality = info->quality; + cinfo.density_unit = info->densityUnit; + cinfo.X_density = info->xDensity; + cinfo.Y_density = info->yDensity; + } + else + { + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(image2, &xDpi, &yDpi); + quality = 80; + cinfo.density_unit = 1; + cinfo.X_density = xDpi; + cinfo.Y_density = yDpi; + } + + jpeg_set_quality(&cinfo, (int)quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + while (cinfo.next_scanline < cinfo.image_height) + { + uint8_t* pEx = data + (HGSize)cinfo.next_scanline * (HGSize)imgInfo.widthStep; + jpeg_write_scanlines(&cinfo, &pEx, 1); + } + + jpeg_finish_compress(&cinfo); + + HGBase_SetImageROI(image, &roi); + HGBase_DestroyImage(image2); + image2 = NULL; + jpeg_destroy_compress(&cinfo); + + HGResult ret = HGBase_CreateBuffer(outSize, buffer); + if (HGBASE_ERR_OK == ret) + { + HGByte* bufferData = NULL; + HGBase_GetBufferData(*buffer, &bufferData); + memcpy(bufferData, outbuffer, outSize); + } + + // 只有libjpeg为静态库的时候,才能用free + // 否则应该使用jpeg_free_large(NULL, outbuffer, 0); + jpeg_free_large(NULL, outbuffer, 0); + return ret; +} diff --git a/app/modules/imgfmt/HGJpeg.h b/app/modules/imgfmt/HGJpeg.h new file mode 100644 index 0000000..fdf9a94 --- /dev/null +++ b/app/modules/imgfmt/HGJpeg.h @@ -0,0 +1,55 @@ +#ifndef __HGJPEG_H__ +#define __HGJPEG_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" +#include "../base/HGBuffer.h" + +/* 颜色空间 */ +#define HGIMGFMT_JPEGCLRSPACE_UNKNOWN 0L +#define HGIMGFMT_JPEGCLRSPACE_GRAYSCALE 1L +#define HGIMGFMT_JPEGCLRSPACE_RGB 2L + +/* 分辨率单位 */ +#define HGIMGFMT_JPEGDENUNIT_INCH 1L /* 英寸 */ +#define HGIMGFMT_JPEGDENUNIT_CENTIMETER 2L /* 厘米 */ + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUInt numComponents; /* 颜色数量 */ + HGUInt colorSpace; /* 颜色空间, 见HGIMGFMT_JPEGCLRSPACE_* */ + HGByte densityUnit; /* 分辨率单位, 见HGIMGFMT_JPEGDENUNIT_* */ + HGUShort xDensity; /* 分辨率x值 */ + HGUShort yDensity; /* 分辨率y值 */ +}HGJpegLoadInfo; + +typedef struct +{ + HGUInt quality; /* 压缩质量, 0-100 */ + HGByte densityUnit; /* 分辨率单位, 见HGIMGFMT_JPEGDENUNIT_* */ + HGUShort xDensity; /* 分辨率x值 */ + HGUShort yDensity; /* 分辨率y值 */ +}HGJpegSaveInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckJpegFile(const HGChar* fileName, HGBool *isJpeg); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadJpegImage(const HGChar* fileName, HGJpegLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadJpegImageFromBuffer(HGBuffer buffer, HGJpegLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveJpegImage(HGImage image, const HGJpegSaveInfo* info, const HGChar* fileName); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveJpegImageToBuffer(HGImage image, const HGJpegSaveInfo* info, HGBuffer *buffer); + +#endif /* __HGJPEG_H__ */ \ No newline at end of file diff --git a/app/modules/imgfmt/HGOfd.cpp b/app/modules/imgfmt/HGOfd.cpp new file mode 100644 index 0000000..536ae74 --- /dev/null +++ b/app/modules/imgfmt/HGOfd.cpp @@ -0,0 +1,173 @@ +#include "HGOfd.h" +#include "HGOfdImpl.hpp" + +HGResult HGAPI HGImgFmt_CheckOfdFile(const HGChar* fileName, HGBool* isOfd) +{ + if (NULL == fileName || NULL == isOfd) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOfdReader reader = NULL; + HGResult ret = HGImgFmt_OpenOfdReader(fileName, &reader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + *isOfd = HGTRUE; + HGImgFmt_CloseOfdReader(reader); + return ret; +} + +HGResult HGAPI HGImgFmt_OpenOfdReader(const HGChar* fileName, HGOfdReader* reader) +{ + if (NULL == fileName || NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOfdReaderImpl* ofdReaderImpl = new HGOfdReaderImpl; + HGResult ret = ofdReaderImpl->Open(fileName); + if (HGBASE_ERR_OK != ret) + { + delete ofdReaderImpl; + return ret; + } + + *reader = (HGOfdReader)ofdReaderImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_CloseOfdReader(HGOfdReader reader) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOfdReaderImpl* ofdReaderImpl = (HGOfdReaderImpl *)reader; + HGResult ret = ofdReaderImpl->Close(); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + delete ofdReaderImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_GetOfdPageCount(HGOfdReader reader, HGUInt* count) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOfdReaderImpl* ofdReaderImpl = (HGOfdReaderImpl*)reader; + return ofdReaderImpl->GetPageCount(count); +} + +HGResult HGAPI HGImgFmt_GetOfdPageInfo(HGOfdReader reader, HGUInt page, HGOfdPageInfo* info) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOfdReaderImpl* ofdReaderImpl = (HGOfdReaderImpl*)reader; + return ofdReaderImpl->GetPageInfo(page, info); +} + +HGResult HGAPI HGImgFmt_LoadImageFromOfdReader(HGOfdReader reader, HGUInt page, HGFloat xScale, HGFloat yScale, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOfdReaderImpl* ofdReaderImpl = (HGOfdReaderImpl*)reader; + return ofdReaderImpl->LoadImage(page, xScale, yScale, imgType, imgOrigin, image); +} + +HGResult HGAPI HGImgFmt_LoadOfdImage(const HGChar* fileName, HGOfdPageInfo* info, HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + HGOfdReader reader = NULL; + HGResult ret = HGImgFmt_OpenOfdReader(fileName, &reader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (HGBASE_ERR_OK == ret && NULL != info) + ret = HGImgFmt_GetOfdPageInfo(reader, 0, info); + + if (HGBASE_ERR_OK == ret && NULL != image) + ret = HGImgFmt_LoadImageFromOfdReader(reader, 0, 1.0f, 1.0f, imgType, imgOrigin, image); + + HGImgFmt_CloseOfdReader(reader); + return ret; +} + +HGResult HGAPI HGImgFmt_OpenOfdImageWriter(const HGChar* fileName, HGOfdImageWriter* writer) +{ + if (NULL == fileName || NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOfdImageWriterImpl* ofdImageWriterImpl = new HGOfdImageWriterImpl; + HGResult ret = ofdImageWriterImpl->Open(fileName); + if (HGBASE_ERR_OK != ret) + { + delete ofdImageWriterImpl; + return ret; + } + + *writer = (HGOfdImageWriter)ofdImageWriterImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_CloseOfdImageWriter(HGOfdImageWriter writer) +{ + if (NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOfdImageWriterImpl* ofdImageWriterImpl = (HGOfdImageWriterImpl*)writer; + HGResult ret = ofdImageWriterImpl->Close(); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + delete ofdImageWriterImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveJpegImageToOfdImageWriter(HGOfdImageWriter writer, HGImage image, const HGJpegSaveInfo* info) +{ + if (NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOfdImageWriterImpl* ofdImageWriterImpl = (HGOfdImageWriterImpl*)writer; + return ofdImageWriterImpl->SaveJpegImage(image, info); +} + +HGResult HGAPI HGImgFmt_SaveOfdJpegImage(HGImage image, const HGJpegSaveInfo* info, const HGChar* fileName) +{ + HGOfdImageWriter writer = NULL; + HGResult ret = HGImgFmt_OpenOfdImageWriter(fileName, &writer); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGImgFmt_SaveJpegImageToOfdImageWriter(writer, image, info); + HGImgFmt_CloseOfdImageWriter(writer); + return ret; +} \ No newline at end of file diff --git a/app/modules/imgfmt/HGOfd.h b/app/modules/imgfmt/HGOfd.h new file mode 100644 index 0000000..0821508 --- /dev/null +++ b/app/modules/imgfmt/HGOfd.h @@ -0,0 +1,48 @@ +#ifndef __HGOFD_H__ +#define __HGOFD_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" +#include "HGJpeg.h" + +HG_DECLARE_HANDLE(HGOfdReader); +HG_DECLARE_HANDLE(HGOfdImageWriter); + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; + HGUInt height; + HGUInt bpp; +}HGOfdPageInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckOfdFile(const HGChar* fileName, HGBool* isOfd); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenOfdReader(const HGChar* fileName, HGOfdReader* reader); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseOfdReader(HGOfdReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_GetOfdPageCount(HGOfdReader reader, HGUInt* count); + +HGEXPORT HGResult HGAPI HGImgFmt_GetOfdPageInfo(HGOfdReader reader, HGUInt page, HGOfdPageInfo* info); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromOfdReader(HGOfdReader reader, HGUInt page, HGFloat xScale, HGFloat yScale, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadOfdImage(const HGChar* fileName, HGOfdPageInfo* info, HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenOfdImageWriter(const HGChar* fileName, HGOfdImageWriter* writer); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseOfdImageWriter(HGOfdImageWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveJpegImageToOfdImageWriter(HGOfdImageWriter writer, HGImage image, const HGJpegSaveInfo* info); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveOfdJpegImage(HGImage image, const HGJpegSaveInfo* info, const HGChar* fileName); + +#endif /* __HGOFD_H__ */ \ No newline at end of file diff --git a/app/modules/imgfmt/HGOfdImpl.cpp b/app/modules/imgfmt/HGOfdImpl.cpp new file mode 100644 index 0000000..d29d0b0 --- /dev/null +++ b/app/modules/imgfmt/HGOfdImpl.cpp @@ -0,0 +1,914 @@ +#include "HGOfdImpl.hpp" +#include "../base/HGInc.h" +#include "../base/HGInfo.h" +#include "../base/HGUtility.h" +#include "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; + } + +#if defined(HG_CMP_MSC) + if (0 != _access(fileName, 0)) +#else + if (0 != access(fileName, 0)) +#endif + { + return HGBASE_ERR_FILENOTEXIST; + } + + int error = 0; + m_zip = zip_open(StdStringToUtf8(fileName).c_str(), 0, &error); + if (NULL == m_zip) + { + return HGBASE_ERR_FILEERROR; + } + + std::string content; + HGResult ret = ReadXml("Doc_0/Document.xml", content); + if (HGBASE_ERR_OK != ret) + { + zip_close(m_zip); + m_zip = NULL; + return ret; + } + + 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 ret; +} + +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; + HGResult ret = ReadXml(name, content); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + 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 HGIMGFMT_ERR_FAIL; + } + + ret = ReadXml("Doc_0/DocumentRes.xml", content); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + 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 HGIMGFMT_ERR_FAIL; + } + + char img_name[128]; + sprintf(img_name, "Doc_0/Res/%s", imgName.c_str()); + + HGJpegLoadInfo jpegInfo; + ret = ReadJpeg(img_name, &jpegInfo, 0, 0, 0, 0, NULL); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + info->width = jpegInfo.width; + info->height = jpegInfo.height; + info->bpp = jpegInfo.numComponents * 8; + 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 (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + + 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; + HGResult ret = ReadXml(name, content); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + 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 HGIMGFMT_ERR_FAIL; + } + + ret = ReadXml("Doc_0/DocumentRes.xml", content); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + 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 HGIMGFMT_ERR_FAIL; + } + + char img_name[128]; + sprintf(img_name, "Doc_0/Res/%s", imgName.c_str()); + ret = ReadJpeg(img_name, NULL, xScale, yScale, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + return ret; +} + +HGResult 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 HGIMGFMT_ERR_FAIL; + } + + zip_file* file = zip_fopen(m_zip, name, ZIP_FL_NOCASE); + if (NULL == file) + { + return HGIMGFMT_ERR_FAIL; + } + + char* s = (char*)malloc((size_t)size + 1); + if (NULL == s) + { + zip_fclose(file); + return HGBASE_ERR_OUTOFMEMORY; + } + + zip_int64_t did_read = zip_fread(file, s, size); + if (did_read != size) + { + free(s); + zip_fclose(file); + return HGIMGFMT_ERR_FAIL; + } + + s[size] = 0; + content = s; + + free(s); + zip_fclose(file); + return HGBASE_ERR_OK; +} + +HGResult HGOfdReaderImpl::ReadJpeg(const char* name, HGJpegLoadInfo* info, 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 HGIMGFMT_ERR_FAIL; + } + + zip_file* file = zip_fopen(m_zip, name, ZIP_FL_NOCASE); + if (NULL == file) + { + return HGIMGFMT_ERR_FAIL; + } + + unsigned char* content = (unsigned char*)malloc((size_t)size); + if (NULL == content) + { + zip_fclose(file); + return HGBASE_ERR_OUTOFMEMORY; + } + + zip_int64_t did_read = zip_fread(file, content, size); + if (did_read != size) + { + free(content); + zip_fclose(file); + return HGIMGFMT_ERR_FAIL; + } + + HGBuffer buffer = NULL; + HGBase_CreateBufferWithData(content, (size_t)size, &buffer); + HGResult ret = HGImgFmt_LoadJpegImageFromBuffer(buffer, info, imgType, imgOrigin, image); + HGBase_DestroyBuffer(buffer); + + free(content); + zip_fclose(file); + return 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) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOfdImageWriterImpl::Open: zip_open fail, %s", fileName); + return HGBASE_ERR_ACCESSDENIED; + } + + zip_add_dir(m_zip, "Doc_0"); + zip_add_dir(m_zip, "Doc_0/Pages"); + zip_add_dir(m_zip, "Doc_0/Res"); + + HGResult ret = AddOfdXml(); + if (HGBASE_ERR_OK != ret) + { + zip_close(m_zip); + m_zip = NULL; + return ret; + } + + ret = AddPublicResXml(); + if (HGBASE_ERR_OK != ret) + { + zip_close(m_zip); + m_zip = NULL; + return ret; + } + + return ret; +} + +HGResult HGOfdImageWriterImpl::Close() +{ + if (NULL == m_zip) + { + return HGBASE_ERR_FAIL; + } + + AddDocXml(); + AddDocResXml(); + + zip_close(m_zip); + m_zip = NULL; + + // 清理临时文件 + std::list::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) +{ + HGChar name[128]; + sprintf(name, "Doc_0/Res/image_%u.jpg", m_curImgIndex); + HGResult ret = AddJpegImageFile(image, info, name); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(image, &xDpi, &yDpi); + if (NULL != info) + { + if (HGIMGFMT_JPEGDENUNIT_INCH == info->densityUnit) + { + xDpi = info->xDensity; + yDpi = info->yDensity; + } + else if (HGIMGFMT_JPEGDENUNIT_CENTIMETER == info->densityUnit) + { + xDpi = (uint32_t)((double)info->xDensity / 0.393700787 + 0.5); + yDpi = (uint32_t)((double)info->yDensity / 0.393700787 + 0.5); + } + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + HGFloat physicalWidth = 25.4f * (HGFloat)imgInfo.width / (HGFloat)xDpi; + HGFloat physicalHeight = 25.4f * (HGFloat)imgInfo.height / (HGFloat)yDpi; + + AddContentXmlFile(m_curImgIndex, physicalWidth, physicalHeight); + ++m_curImgIndex; + return HGBASE_ERR_OK; +} + +HGResult 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("ofd"); + docInfo->InsertEndChild(creator); + + tinyxml2::XMLElement* createVersion = xmlDoc.NewElement("ofd:CreatorVersion"); + createVersion->SetText("1.0.0"); + docInfo->InsertEndChild(createVersion); + + return AddXmlFile(xmlDoc, "OFD.xml"); +} + +HGResult 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"); +} + +HGResult 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"); +} + +HGResult 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"); +} + +HGResult HGOfdImageWriterImpl::AddXmlFile(tinyxml2::XMLDocument& xmlDoc, const HGChar* name) +{ + HGChar tmpName[256]; + HGBase_GetTmpFileName(NULL, tmpName, 256); + if (tinyxml2::XML_SUCCESS != xmlDoc.SaveFile(tmpName)) + { + return HGIMGFMT_ERR_FAIL; + } + + zip_source_t* s = zip_source_file(m_zip, tmpName, 0, 0); + if (NULL == s) + { + HGBase_DeleteFile(tmpName); + return HGIMGFMT_ERR_FAIL; + } + + 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 HGIMGFMT_ERR_FAIL; + } + + m_tmpFiles.push_back(tmpName); + return HGBASE_ERR_OK; +} + +HGResult HGOfdImageWriterImpl::AddJpegImageFile(HGImage image, const HGJpegSaveInfo* info, const HGChar* name) +{ + HGChar tmpName[256]; + HGBase_GetTmpFileName(NULL, tmpName, 256); + HGResult ret = HGImgFmt_SaveJpegImage(image, info, tmpName); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + zip_source_t* s = zip_source_file(m_zip, tmpName, 0, 0); + if (NULL == s) + { + HGBase_DeleteFile(tmpName); + return HGIMGFMT_ERR_FAIL; + } + + zip_int64_t rc = zip_file_add(m_zip, name, s, ZIP_FL_OVERWRITE); + if (rc < 0) + { + zip_source_free(s); + HGBase_DeleteFile(tmpName); + return HGIMGFMT_ERR_FAIL; + } + + m_tmpFiles.push_back(tmpName); + return HGBASE_ERR_OK; +} + +HGResult 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[256]; + sprintf(name, "%s/Content.xml", dir); + return AddXmlFile(xmlDoc, name); +} diff --git a/app/modules/imgfmt/HGOfdImpl.hpp b/app/modules/imgfmt/HGOfdImpl.hpp new file mode 100644 index 0000000..795d5b6 --- /dev/null +++ b/app/modules/imgfmt/HGOfdImpl.hpp @@ -0,0 +1,61 @@ +#ifndef __HGOFDIMPL_HPP__ +#define __HGOFDIMPL_HPP__ + +#include "HGOfd.h" +extern "C" +{ +#include "zip.h" +}; +#include "tinyxml2.h" +#include +#include +#include + +class HGOfdReaderImpl +{ +public: + HGOfdReaderImpl(); + ~HGOfdReaderImpl(); + + HGResult Open(const HGChar* fileName); + HGResult Close(); + HGResult GetPageCount(HGUInt* count); + HGResult GetPageInfo(HGUInt page, HGOfdPageInfo* info); + HGResult LoadImage(HGUInt page, HGFloat xScale, HGFloat yScale, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +private: + HGResult ReadXml(const char *name, std::string &content); + HGResult ReadJpeg(const char* name, HGJpegLoadInfo *info, HGFloat xScale, HGFloat yScale, HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +private: + zip* m_zip; + std::vector m_contentNames; +}; + +class HGOfdImageWriterImpl +{ +public: + HGOfdImageWriterImpl(); + ~HGOfdImageWriterImpl(); + + HGResult Open(const HGChar* fileName); + HGResult Close(); + HGResult SaveJpegImage(HGImage image, const HGJpegSaveInfo* info); + +private: + HGResult AddOfdXml(); + HGResult AddDocXml(); + HGResult AddDocResXml(); + HGResult AddPublicResXml(); + HGResult AddXmlFile(tinyxml2::XMLDocument &xmlDoc, const HGChar *name); + HGResult AddJpegImageFile(HGImage image, const HGJpegSaveInfo* info, const HGChar* name); + HGResult AddContentXmlFile(HGUInt index, HGFloat physicalWidth, HGFloat physicalHeight); + +private: + zip* m_zip; + std::list m_tmpFiles; + HGUInt m_curImgIndex; +}; + +#endif /* __HGOFDIMPL_HPP__ */ \ No newline at end of file diff --git a/app/modules/imgfmt/HGPdf.cpp b/app/modules/imgfmt/HGPdf.cpp new file mode 100644 index 0000000..c383605 --- /dev/null +++ b/app/modules/imgfmt/HGPdf.cpp @@ -0,0 +1,173 @@ +#include "HGPdf.h" +#include "HGPdfImpl.hpp" + +HGResult HGAPI HGImgFmt_CheckPdfFile(const HGChar* fileName, HGBool* isPdf) +{ + if (NULL == fileName || NULL == isPdf) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPdfReader reader = NULL; + HGResult ret = HGImgFmt_OpenPdfReader(fileName, &reader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + *isPdf = HGTRUE; + HGImgFmt_ClosePdfReader(reader); + return ret; +} + +HGResult HGAPI HGImgFmt_OpenPdfReader(const HGChar* fileName, HGPdfReader* reader) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPdfReaderImpl* pdfReaderImpl = new HGPdfReaderImpl; + HGResult ret = pdfReaderImpl->Open(fileName); + if (HGBASE_ERR_OK != ret) + { + delete pdfReaderImpl; + return ret; + } + + *reader = (HGPdfReader)pdfReaderImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_ClosePdfReader(HGPdfReader reader) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPdfReaderImpl* pdfReaderImpl = (HGPdfReaderImpl*)reader; + HGResult ret = pdfReaderImpl->Close(); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + delete pdfReaderImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_GetPdfPageCount(HGPdfReader reader, HGUInt* count) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPdfReaderImpl* pdfReaderImpl = (HGPdfReaderImpl*)reader; + return pdfReaderImpl->GetPageCount(count); +} + +HGResult HGAPI HGImgFmt_GetPdfPageInfo(HGPdfReader reader, HGUInt page, HGPdfPageInfo* info) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPdfReaderImpl* pdfReaderImpl = (HGPdfReaderImpl*)reader; + return pdfReaderImpl->GetPageInfo(page, info); +} + +HGResult HGAPI HGImgFmt_LoadImageFromPdfReader(HGPdfReader reader, HGUInt page, HGFloat xScale, HGFloat yScale, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPdfReaderImpl* pdfReaderImpl = (HGPdfReaderImpl*)reader; + return pdfReaderImpl->LoadImage(page, xScale, yScale, imgType, imgOrigin, image); +} + +HGResult HGAPI HGImgFmt_LoadPdfImage(const HGChar* fileName, HGPdfPageInfo* info, HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + HGPdfReader reader = NULL; + HGResult ret = HGImgFmt_OpenPdfReader(fileName, &reader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (HGBASE_ERR_OK == ret && NULL != info) + ret = HGImgFmt_GetPdfPageInfo(reader, 0, info); + + if (HGBASE_ERR_OK == ret && NULL != image) + ret = HGImgFmt_LoadImageFromPdfReader(reader, 0, 1.0f, 1.0f, imgType, imgOrigin, image); + + HGImgFmt_ClosePdfReader(reader); + return ret; +} + +HGResult HGAPI HGImgFmt_OpenPdfImageWriter(const HGChar* fileName, HGPdfImageWriter* writer) +{ + if (NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPdfImageWriterImpl* pdfImageWriterImpl = new HGPdfImageWriterImpl; + HGResult ret = pdfImageWriterImpl->Open(fileName); + if (HGBASE_ERR_OK != ret) + { + delete pdfImageWriterImpl; + return ret; + } + + *writer = (HGPdfImageWriter)pdfImageWriterImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_ClosePdfImageWriter(HGPdfImageWriter writer) +{ + if (NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPdfImageWriterImpl* pdfImageWriterImpl = (HGPdfImageWriterImpl*)writer; + HGResult ret = pdfImageWriterImpl->Close(); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + delete pdfImageWriterImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveJpegImageToPdfImageWriter(HGPdfImageWriter writer, HGImage image, const HGJpegSaveInfo* info) +{ + if (NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPdfImageWriterImpl* pdfImageWriterImpl = (HGPdfImageWriterImpl*)writer; + return pdfImageWriterImpl->SaveJpegImage(image, info); +} + +HGResult HGAPI HGImgFmt_SavePdfJpegImage(HGImage image, const HGJpegSaveInfo* info, const HGChar* fileName) +{ + HGPdfImageWriter writer = NULL; + HGResult ret = HGImgFmt_OpenPdfImageWriter(fileName, &writer); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGImgFmt_SaveJpegImageToPdfImageWriter(writer, image, info); + HGImgFmt_ClosePdfImageWriter(writer); + return ret; +} diff --git a/app/modules/imgfmt/HGPdf.h b/app/modules/imgfmt/HGPdf.h new file mode 100644 index 0000000..7dac61b --- /dev/null +++ b/app/modules/imgfmt/HGPdf.h @@ -0,0 +1,48 @@ +#ifndef __HGPDF_H__ +#define __HGPDF_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" +#include "HGJpeg.h" + +HG_DECLARE_HANDLE(HGPdfReader); +HG_DECLARE_HANDLE(HGPdfImageWriter); + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; + HGUInt height; + HGUInt bpp; +}HGPdfPageInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckPdfFile(const HGChar* fileName, HGBool* isPdf); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenPdfReader(const HGChar* fileName, HGPdfReader* reader); + +HGEXPORT HGResult HGAPI HGImgFmt_ClosePdfReader(HGPdfReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_GetPdfPageCount(HGPdfReader reader, HGUInt* count); + +HGEXPORT HGResult HGAPI HGImgFmt_GetPdfPageInfo(HGPdfReader reader, HGUInt page, HGPdfPageInfo *info); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromPdfReader(HGPdfReader reader, HGUInt page, HGFloat xScale, HGFloat yScale, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadPdfImage(const HGChar* fileName, HGPdfPageInfo *info, HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenPdfImageWriter(const HGChar* fileName, HGPdfImageWriter* writer); + +HGEXPORT HGResult HGAPI HGImgFmt_ClosePdfImageWriter(HGPdfImageWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveJpegImageToPdfImageWriter(HGPdfImageWriter writer, HGImage image, const HGJpegSaveInfo* info); + +HGEXPORT HGResult HGAPI HGImgFmt_SavePdfJpegImage(HGImage image, const HGJpegSaveInfo* info, const HGChar* fileName); + +#endif /* __HGPDF_H__ */ \ No newline at end of file diff --git a/app/modules/imgfmt/HGPdfImpl.cpp b/app/modules/imgfmt/HGPdfImpl.cpp new file mode 100644 index 0000000..b91f8d9 --- /dev/null +++ b/app/modules/imgfmt/HGPdfImpl.cpp @@ -0,0 +1,890 @@ +#include "HGPdfImpl.hpp" +#include "../base/HGInc.h" +#include "../base/HGUtility.h" +#include "../base/HGInfo.h" +#include "HGString.h" +#include +#include + +HGPdfReaderImpl::HGPdfReaderImpl() +{ + m_dll = NULL; + m_pContext = NULL; + m_pDoc = NULL; +} + +HGPdfReaderImpl::~HGPdfReaderImpl() +{ + +} + +HGResult HGPdfReaderImpl::Open(const HGChar* fileName) +{ + if (NULL != m_pDoc) + { + return HGBASE_ERR_FAIL; + } + + if (NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + if (0 != _access(fileName, 0)) +#else + if (0 != access(fileName, 0)) +#endif + { + return HGBASE_ERR_FILENOTEXIST; + } + + HGBool isPdfFile = HGFALSE; + FILE* file = fopen(fileName, "r"); + if (NULL != file) + { + HGByte data[4]; + size_t len = fread(data, 1, 4, file); + if (4 == len && 0 == memcmp(data, "%PDF", 4)) + { + isPdfFile = HGTRUE; + } + + fclose(file); + } + else + { + return HGBASE_ERR_ACCESSDENIED; + } + + if (!isPdfFile) + { + return HGBASE_ERR_FILEERROR; + } + + assert(NULL == m_dll); + + HGChar moduleName[256]; + HGBase_GetModuleName((void *)HGImgFmt_OpenPdfReader, moduleName, 256); + HGChar dllPath[256]; + HGBase_GetFilePath(moduleName, dllPath, 256); + +#if defined(HG_CMP_MSC) + strcat(dllPath, "libmupdf.dll"); +#else + strcat(dllPath, "libmupdf.so"); +#endif + HGResult ret = HGBase_CreateDll(dllPath, &m_dll); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + fz_context* pContext = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT); + if (NULL == pContext) + { + HGBase_DestroyDll(m_dll); + m_dll = NULL; + return HGIMGFMT_ERR_FAIL; + } + + ret = HGIMGFMT_ERR_FAIL; + fz_try(pContext) + { + fz_register_document_handlers(pContext); + fz_document* pDoc = fz_open_document(pContext, StdStringToUtf8(fileName).c_str()); + + m_pContext = pContext; + m_pDoc = pDoc; + ret = HGBASE_ERR_OK; + } + fz_catch(pContext) + { + fz_drop_context(pContext); + pContext = NULL; + HGBase_DestroyDll(m_dll); + m_dll = NULL; + } + + return ret; +} + +HGResult HGPdfReaderImpl::Close() +{ + if (NULL == m_pDoc) + { + return HGBASE_ERR_FAIL; + } + + fz_drop_document(m_pContext, m_pDoc); + m_pDoc = NULL; + fz_drop_context(m_pContext); + m_pContext = NULL; + HGBase_DestroyDll(m_dll); + m_dll = NULL; + return HGBASE_ERR_OK; +} + +HGResult HGPdfReaderImpl::GetPageCount(HGUInt* count) +{ + if (NULL == m_pDoc) + { + return HGBASE_ERR_FAIL; + } + + if (NULL == count) + { + return HGBASE_ERR_INVALIDARG; + } + + HGResult ret = HGIMGFMT_ERR_FAIL; + fz_try(m_pContext) + { + *count = (uint32_t)fz_count_pages(m_pContext, m_pDoc); + ret = HGBASE_ERR_OK; + } + fz_catch(m_pContext) + { + + } + + return ret; +} + +HGResult HGPdfReaderImpl::GetPageInfo(HGUInt page, HGPdfPageInfo* info) +{ + if (NULL == m_pDoc) + { + return HGBASE_ERR_FAIL; + } + + if (NULL == info) + { + return HGBASE_ERR_INVALIDARG; + } + + HGResult ret = HGIMGFMT_ERR_FAIL; + fz_page* fzpage = NULL; + + fz_try(m_pContext) + { + fzpage = fz_load_page(m_pContext, m_pDoc, (int)page); + pdf_page* page = pdf_page_from_fz_page(m_pContext, fzpage); + if (NULL != page) + { + fz_rect pdfRect = pdf_bound_page(m_pContext, page); + info->width = ceil(pdfRect.x1); + info->height = ceil(pdfRect.y1); + info->bpp = 24; + ret = HGBASE_ERR_OK; + } + } + fz_catch(m_pContext) + { + + } + + if (NULL != fzpage) + fz_drop_page(m_pContext, fzpage); + return ret; +} + +HGResult HGPdfReaderImpl::LoadImage(HGUInt page, HGFloat xScale, HGFloat yScale, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == m_pDoc) + { + return HGBASE_ERR_FAIL; + } + + if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGResult ret = HGIMGFMT_ERR_FAIL; + fz_pixmap* pix = NULL; + + fz_try(m_pContext) + { + fz_matrix ctm = fz_scale(xScale, yScale); + pix = fz_new_pixmap_from_page_number(m_pContext, m_pDoc, (int)page, + ctm, fz_device_rgb(m_pContext), 0); + + int width = fz_pixmap_width(m_pContext, pix); + int height = fz_pixmap_height(m_pContext, pix); + + if (0 == imgType) + imgType = HGBASE_IMGTYPE_RGB; + + if (imgOrigin == 0) + imgOrigin = HGBASE_IMGORIGIN_TOP; + + HGImage image2 = NULL; + HGImageInfo imgInfo = { (uint32_t)width, (uint32_t)height, HGBASE_IMGTYPE_RGB, (uint32_t)pix->stride, HGBASE_IMGORIGIN_TOP }; + if (HGBASE_ERR_OK == HGBase_CreateImageWithData(pix->samples, &imgInfo, &image2)) + { + ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); + HGBase_DestroyImage(image2); + } + + } + fz_catch(m_pContext) + { + + } + + if (NULL != pix) + fz_drop_pixmap(m_pContext, pix); + return ret; +} + +fz_context* HGPdfReaderImpl::fz_new_context_imp(const fz_alloc_context* alloc, const fz_locks_context* locks, size_t max_store, const char* version) +{ + typedef fz_context* (*Func)(const fz_alloc_context*, const fz_locks_context*, size_t, const char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_new_context_imp", (HGPointer*)&func); + if (NULL == func) + { + return NULL; + } + + return func(alloc, locks, max_store, version); +} + +void HGPdfReaderImpl::fz_register_document_handlers(fz_context* ctx) +{ + typedef void (*Func)(fz_context*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_register_document_handlers", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(ctx); +} + +fz_document* HGPdfReaderImpl::fz_open_document(fz_context* ctx, const char* filename) +{ + typedef fz_document* (*Func)(fz_context*, const char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_open_document", (HGPointer*)&func); + if (NULL == func) + { + return NULL; + } + + return func(ctx, filename); +} + +void HGPdfReaderImpl::fz_drop_context(fz_context* ctx) +{ + typedef void (*Func)(fz_context*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_drop_context", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(ctx); +} + +void HGPdfReaderImpl::fz_drop_document(fz_context* ctx, fz_document* doc) +{ + typedef void (*Func)(fz_context*, fz_document*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_drop_document", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(ctx, doc); +} + +int HGPdfReaderImpl::fz_count_pages(fz_context* ctx, fz_document* doc) +{ + typedef int (*Func)(fz_context*, fz_document*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_count_pages", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(ctx, doc); +} + +fz_page* HGPdfReaderImpl::fz_load_page(fz_context* ctx, fz_document* doc, int number) +{ + typedef fz_page* (*Func)(fz_context*, fz_document* doc, int); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_load_page", (HGPointer*)&func); + if (NULL == func) + { + return NULL; + } + + return func(ctx, doc, number); +} + +pdf_page* HGPdfReaderImpl::pdf_page_from_fz_page(fz_context* ctx, fz_page* ptr) +{ + typedef pdf_page* (*Func)(fz_context*, fz_page*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "pdf_page_from_fz_page", (HGPointer*)&func); + if (NULL == func) + { + return NULL; + } + + return func(ctx, ptr); +} + +fz_rect HGPdfReaderImpl::pdf_bound_page(fz_context* ctx, pdf_page* page) +{ + typedef fz_rect (*Func)(fz_context*, pdf_page*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "pdf_bound_page", (HGPointer*)&func); + if (NULL == func) + { + fz_rect rect = {0, 0, 0, 0}; + return rect; + } + + return func(ctx, page); +} + +void HGPdfReaderImpl::fz_drop_page(fz_context* ctx, fz_page* page) +{ + typedef void (*Func)(fz_context*, fz_page*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_drop_page", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(ctx, page); +} + +fz_matrix HGPdfReaderImpl::fz_scale(float sx, float sy) +{ + typedef fz_matrix (*Func)(float, float); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_scale", (HGPointer*)&func); + if (NULL == func) + { + fz_matrix matrix = { 0, 0, 0, 0, 0, 0 }; + return matrix; + } + + return func(sx, sy); +} + +fz_pixmap* HGPdfReaderImpl::fz_new_pixmap_from_page_number(fz_context* ctx, fz_document* doc, int number, fz_matrix ctm, fz_colorspace* cs, int alpha) +{ + typedef fz_pixmap* (*Func)(fz_context*, fz_document*, int, fz_matrix, fz_colorspace*, int); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_new_pixmap_from_page_number", (HGPointer*)&func); + if (NULL == func) + { + return NULL; + } + + return func(ctx, doc, number, ctm, cs, alpha); +} + +fz_colorspace* HGPdfReaderImpl::fz_device_rgb(fz_context* ctx) +{ + typedef fz_colorspace* (*Func)(fz_context*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_device_rgb", (HGPointer*)&func); + if (NULL == func) + { + return NULL; + } + + return func(ctx); +} + +int HGPdfReaderImpl::fz_pixmap_width(fz_context* ctx, const fz_pixmap* pix) +{ + typedef int (*Func)(fz_context*, const fz_pixmap*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_pixmap_width", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(ctx, pix); +} + +int HGPdfReaderImpl::fz_pixmap_height(fz_context* ctx, const fz_pixmap* pix) +{ + typedef int (*Func)(fz_context*, const fz_pixmap*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_pixmap_height", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(ctx, pix); +} + +void HGPdfReaderImpl::fz_drop_pixmap(fz_context* ctx, fz_pixmap* pix) +{ + typedef void (*Func)(fz_context*, fz_pixmap*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_drop_pixmap", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(ctx, pix); +} + +fz_jmp_buf* HGPdfReaderImpl::fz_push_try(fz_context* ctx) +{ + typedef fz_jmp_buf* (*Func)(fz_context*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_push_try", (HGPointer*)&func); + if (NULL == func) + { + return NULL; + } + + return func(ctx); +} + +int HGPdfReaderImpl::fz_do_try(fz_context* ctx) +{ + typedef int (*Func)(fz_context*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_do_try", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(ctx); +} + +int HGPdfReaderImpl::fz_do_catch(fz_context* ctx) +{ + typedef int (*Func)(fz_context*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "fz_do_catch", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(ctx); +} + + +#if defined(HG_CMP_MSC) +static WCHAR* GetUnicodeStr(const char* text) +{ + int len = ::MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0); + WCHAR* pUnicode = new WCHAR[len]; + ::MultiByteToWideChar(CP_ACP, 0, text, -1, pUnicode, len); + return pUnicode; +} +static uint32_t GetUnicodeStrLen(const WCHAR* pUnicode) +{ + return (uint32_t)wcslen(pUnicode); +} +#else +static uint16_t* GetUnicodeStr(const char* text) +{ + if (0 == *text) + { + uint16_t* pUnicode = new uint16_t[1]; + *pUnicode = 0; + return pUnicode; + } + + uint16_t* pUnicode = new uint16_t[strlen(text) + 2]; + memset(pUnicode, 0, sizeof(uint16_t) * (strlen(text) + 2)); + + iconv_t cd = iconv_open("UNICODE//IGNORE", "UTF-8"); + if ((iconv_t)-1 != cd) + { + char* inbuf = (char*)text; + size_t inbytes = strlen(text); + char* outbuf = (char*)pUnicode; + size_t outsize = sizeof(uint16_t) * (strlen(text) + 1); + + iconv(cd, &inbuf, &inbytes, &outbuf, &outsize); + iconv_close(cd); + } + + return pUnicode; +} +static uint32_t GetUnicodeStrLen(const uint16_t* pUnicode) +{ + uint32_t i = 0; + while (0 != pUnicode[i]) + { + ++i; + } + + return i; +} +#endif + +HGPdfImageWriterImpl::HGPdfImageWriterImpl() +{ + m_dll = NULL; + m_pPdf = NULL; +} + +HGPdfImageWriterImpl::~HGPdfImageWriterImpl() +{ + +} + +HGResult HGPdfImageWriterImpl::Open(const HGChar* fileName) +{ + if (NULL != m_pPdf) + { + return HGBASE_ERR_FAIL; + } + + if (NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + + assert(NULL == m_dll); + + HGChar moduleName[256]; + HGBase_GetModuleName((void*)HGImgFmt_OpenPdfImageWriter, moduleName, 256); + HGChar dllPath[256]; + HGBase_GetFilePath(moduleName, dllPath, 256); + +#if defined(HG_CMP_MSC) + strcat(dllPath, "pdflib.dll"); +#else + strcat(dllPath, "libpdf.so"); +#endif + HGResult ret = HGBase_CreateDll(dllPath, &m_dll); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + PDF* p = PDF_new(); + if (NULL == p) + { + HGBase_DestroyDll(m_dll); + m_dll = NULL; + return HGIMGFMT_ERR_FAIL; + } + +#if defined(HG_CMP_MSC) + WCHAR* pUnicode = GetUnicodeStr(fileName); +#else + uint16_t* pUnicode = GetUnicodeStr(fileName); +#endif + + PDF_TRY(p) + { + PDF_set_parameter(p, "compatibility", "1.4"); + PDF_set_parameter(p, "errorpolicy", "return"); + PDF_set_parameter(p, "hypertextencoding", "host"); + +#if defined(HG_CMP_MSC) + if (-1 == PDF_begin_document(p, (const char*)pUnicode, (int)(GetUnicodeStrLen(pUnicode) * sizeof(WCHAR)), "")) +#else + if (-1 == PDF_begin_document(p, (const char*)pUnicode, (int)(GetUnicodeStrLen(pUnicode) * sizeof(uint16_t)), "")) +#endif + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGPdfImageWriterImpl::Open: PDF_begin_document fail, %s", fileName); + + delete[] pUnicode; + PDF_delete(p); + HGBase_DestroyDll(m_dll); + m_dll = NULL; + return HGBASE_ERR_ACCESSDENIED; + } + } + PDF_CATCH(p) + { + delete[] pUnicode; + PDF_delete(p); + HGBase_DestroyDll(m_dll); + m_dll = NULL; + return HGIMGFMT_ERR_FAIL; + } + + delete[] pUnicode; + m_pPdf = p; + return HGBASE_ERR_OK; +} + +HGResult HGPdfImageWriterImpl::Close() +{ + if (NULL == m_pPdf) + { + return HGBASE_ERR_FAIL; + } + + PDF_TRY(m_pPdf) + { + PDF_end_document(m_pPdf, ""); + } + PDF_CATCH(m_pPdf) + { + + } + + PDF_delete(m_pPdf); + m_pPdf = NULL; + HGBase_DestroyDll(m_dll); + m_dll = NULL; + return HGBASE_ERR_OK; +} + +HGResult HGPdfImageWriterImpl::SaveJpegImage(HGImage image, const HGJpegSaveInfo* info) +{ + if (NULL == m_pPdf) + { + return HGBASE_ERR_FAIL; + } + + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGBuffer buffer = NULL; + HGResult ret = HGImgFmt_SaveJpegImageToBuffer(image, info, &buffer); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + HGByte* imgBuf = NULL; + HGBase_GetBufferData(buffer, &imgBuf); + HGUSize size = 0; + HGBase_GetBufferSize(buffer, &size); + + PDF_TRY(m_pPdf) + { + PDF_create_pvf(m_pPdf, "virtual_file", 0, imgBuf, size, ""); + } + PDF_CATCH(m_pPdf) + { + HGBase_DestroyBuffer(buffer); + return HGIMGFMT_ERR_FAIL; + } + + int img = PDF_load_image(m_pPdf, "auto", "virtual_file", 0, "page 1"); + if (-1 != img) + { + PDF_begin_page_ext(m_pPdf, 0.0, 0.0, ""); + PDF_fit_image(m_pPdf, img, 0.0, 0.0, "adjustpage"); + PDF_end_page_ext(m_pPdf, ""); + PDF_close_image(m_pPdf, img); + } + + PDF_delete_pvf(m_pPdf, "virtual_file", 0); + + HGBase_DestroyBuffer(buffer); + return HGBASE_ERR_OK; +} + +PDF* HGPdfImageWriterImpl::PDF_new(void) +{ + typedef PDF* (PDFLIB_CALL *Func)(); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_new", (HGPointer*)&func); + if (NULL == func) + { + return NULL; + } + + return func(); +} + +void HGPdfImageWriterImpl::PDF_set_parameter(PDF* p, const char* key, const char* value) +{ + typedef void (PDFLIB_CALL* Func)(PDF*, const char*, const char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_set_parameter", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(p, key, value); +} + +int HGPdfImageWriterImpl::PDF_begin_document(PDF* p, const char* filename, int len, const char* optlist) +{ + typedef int (PDFLIB_CALL* Func)(PDF*, const char*, int, const char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_begin_document", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(p, filename, len, optlist); +} + +void HGPdfImageWriterImpl::PDF_delete(PDF* p) +{ + typedef void (PDFLIB_CALL* Func)(PDF*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_delete", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(p); +} + +void HGPdfImageWriterImpl::PDF_end_document(PDF* p, const char* optlist) +{ + typedef void (PDFLIB_CALL* Func)(PDF*, const char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_end_document", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(p, optlist); +} + +void HGPdfImageWriterImpl::PDF_create_pvf(PDF* p, const char* filename, int len, const void* data, size_t size, const char* optlist) +{ + typedef void (PDFLIB_CALL* Func)(PDF*, const char*, int, const void*, size_t, const char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_create_pvf", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(p, filename, len, data, size, optlist); +} + +int HGPdfImageWriterImpl::PDF_load_image(PDF* p, const char* imagetype, const char* filename, int len, const char* optlist) +{ + typedef int (PDFLIB_CALL* Func)(PDF*, const char*, const char*, int, const char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_load_image", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(p, imagetype, filename, len, optlist); +} + +void HGPdfImageWriterImpl::PDF_begin_page_ext(PDF* p, double width, double height, const char* optlist) +{ + typedef void (PDFLIB_CALL* Func)(PDF*, double, double, const char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_begin_page_ext", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(p, width, height, optlist); +} + +void HGPdfImageWriterImpl::PDF_fit_image(PDF* p, int image, double x, double y, const char* optlist) +{ + typedef void (PDFLIB_CALL* Func)(PDF*, int, double, double, const char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_fit_image", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(p, image, x, y, optlist); +} + +void HGPdfImageWriterImpl::PDF_end_page_ext(PDF* p, const char* optlist) +{ + typedef void (PDFLIB_CALL* Func)(PDF*, const char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_end_page_ext", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(p, optlist); +} + +void HGPdfImageWriterImpl::PDF_close_image(PDF* p, int image) +{ + typedef void (PDFLIB_CALL* Func)(PDF*, int); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_close_image", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(p, image); +} + +int HGPdfImageWriterImpl::PDF_delete_pvf(PDF* p, const char* filename, int len) +{ + typedef int (PDFLIB_CALL* Func)(PDF*, const char*, int); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "PDF_delete_pvf", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(p, filename, len); +} + +pdf_jmpbuf* HGPdfImageWriterImpl::pdf_jbuf(PDF* p) +{ + typedef pdf_jmpbuf* (PDFLIB_CALL* Func)(PDF*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "pdf_jbuf", (HGPointer*)&func); + if (NULL == func) + { + return NULL; + } + + return func(p); +} + +int HGPdfImageWriterImpl::pdf_catch(PDF* p) +{ + typedef int (PDFLIB_CALL* Func)(PDF*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "pdf_catch", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(p); +} \ No newline at end of file diff --git a/app/modules/imgfmt/HGPdfImpl.hpp b/app/modules/imgfmt/HGPdfImpl.hpp new file mode 100644 index 0000000..ad0affd --- /dev/null +++ b/app/modules/imgfmt/HGPdfImpl.hpp @@ -0,0 +1,81 @@ +#ifndef __HGPDFIMPL_HPP__ +#define __HGPDFIMPL_HPP__ + +#include "HGPdf.h" +#include "../base/HGDll.h" +#include "mupdf/pdf.h" +#include "mupdf/fitz.h" +#include "pdflib.h" + +class HGPdfReaderImpl +{ +public: + HGPdfReaderImpl(); + ~HGPdfReaderImpl(); + + HGResult Open(const HGChar* fileName); + HGResult Close(); + HGResult GetPageCount(HGUInt* count); + HGResult GetPageInfo(HGUInt page, HGPdfPageInfo* info); + HGResult LoadImage(HGUInt page, HGFloat xScale, HGFloat yScale, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +private: + fz_context* fz_new_context_imp(const fz_alloc_context* alloc, const fz_locks_context* locks, size_t max_store, const char* version); + void fz_register_document_handlers(fz_context* ctx); + fz_document* fz_open_document(fz_context* ctx, const char* filename); + void fz_drop_context(fz_context* ctx); + void fz_drop_document(fz_context* ctx, fz_document* doc); + int fz_count_pages(fz_context* ctx, fz_document* doc); + fz_page* fz_load_page(fz_context* ctx, fz_document* doc, int number); + pdf_page* pdf_page_from_fz_page(fz_context* ctx, fz_page* ptr); + fz_rect pdf_bound_page(fz_context* ctx, pdf_page* page); + void fz_drop_page(fz_context* ctx, fz_page* page); + fz_matrix fz_scale(float sx, float sy); + fz_pixmap* fz_new_pixmap_from_page_number(fz_context* ctx, fz_document* doc, int number, fz_matrix ctm, fz_colorspace* cs, int alpha); + fz_colorspace* fz_device_rgb(fz_context* ctx); + int fz_pixmap_width(fz_context* ctx, const fz_pixmap* pix); + int fz_pixmap_height(fz_context* ctx, const fz_pixmap* pix); + void fz_drop_pixmap(fz_context* ctx, fz_pixmap* pix); + fz_jmp_buf* fz_push_try(fz_context* ctx); + int fz_do_try(fz_context* ctx); + int fz_do_catch(fz_context* ctx); + +private: + HGDll m_dll; + fz_context* m_pContext; + fz_document* m_pDoc; +}; + +class HGPdfImageWriterImpl +{ +public: + HGPdfImageWriterImpl(); + ~HGPdfImageWriterImpl(); + + HGResult Open(const HGChar* fileName); + HGResult Close(); + HGResult SaveJpegImage(HGImage image, const HGJpegSaveInfo* info); + +private: + PDF* PDF_new(void); + void PDF_set_parameter(PDF* p, const char* key, const char* value); + int PDF_begin_document(PDF* p, const char* filename, int len, const char* optlist); + void PDF_delete(PDF* p); + void PDF_end_document(PDF* p, const char* optlist); + void PDF_create_pvf(PDF* p, const char* filename, int len, const void* data, size_t size, const char* optlist); + int PDF_load_image(PDF* p, const char* imagetype, const char* filename, int len, const char* optlist); + void PDF_begin_page_ext(PDF* p, double width, double height, const char* optlist); + void PDF_fit_image(PDF* p, int image, double x, double y, const char* optlist); + void PDF_end_page_ext(PDF* p, const char* optlist); + void PDF_close_image(PDF* p, int image); + int PDF_delete_pvf(PDF* p, const char* filename, int len); + pdf_jmpbuf* pdf_jbuf(PDF* p); + int pdf_catch(PDF* p); + +private: + HGDll m_dll; + PDF* m_pPdf; +}; + +#endif /* __HGPDFIMPL_HPP__ */ \ No newline at end of file diff --git a/app/modules/imgfmt/HGPng.cpp b/app/modules/imgfmt/HGPng.cpp new file mode 100644 index 0000000..271655b --- /dev/null +++ b/app/modules/imgfmt/HGPng.cpp @@ -0,0 +1,462 @@ +#include "HGPng.h" +#include "../base/HGInc.h" +#include "../base/HGInfo.h" +#include "png.h" +#include "pngstruct.h" +#include "pnginfo.h" +#include "pngpriv.h" + +HGResult HGAPI HGImgFmt_CheckPngFile(const HGChar* fileName, HGBool* isPng) +{ + if (NULL == fileName || NULL == isPng) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPngLoadInfo info; + HGResult ret = HGImgFmt_LoadPngImage(fileName, &info, 0, 0, NULL); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + *isPng = HGTRUE; + return ret; +} + +HGResult HGAPI HGImgFmt_LoadPngImage(const HGChar* fileName, HGPngLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL == image) + { + if (0 != imgType || 0 != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + else + { + if (0 != imgType && HGBASE_IMGTYPE_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType + && HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType + && HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + +#if defined(HG_CMP_MSC) + if (0 != _access(fileName, 0)) +#else + if (0 != access(fileName, 0)) +#endif + { + return HGBASE_ERR_FILENOTEXIST; + } + + FILE* file = fopen(fileName, "rb"); + if (NULL == file) + { + return HGBASE_ERR_ACCESSDENIED; + } + + png_byte buf[8] = { 0 }; + if (fread(buf, 1, 8, file) != 8) + { + fclose(file); + file = NULL; + return HGBASE_ERR_FAIL; + } + + if (0 != png_sig_cmp(buf, 0, 8)) + { + fclose(file); + file = NULL; + return HGBASE_ERR_FILEERROR; + } + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (NULL == png_ptr) + { + fclose(file); + file = NULL; + return HGIMGFMT_ERR_FAIL; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (NULL == info_ptr) + { + png_destroy_read_struct(&png_ptr, NULL, NULL); + fclose(file); + file = NULL; + return HGIMGFMT_ERR_FAIL; + } + + uint8_t* buffer = NULL; + uint8_t** rowPointers = NULL; + HGImage image2 = NULL; + + int jmpResult = setjmp(png_jmpbuf(png_ptr)); + if (0 != jmpResult) + { + HGBase_DestroyImage(image2); + image2 = NULL; + free(rowPointers); + rowPointers = NULL; + free(buffer); + buffer = NULL; + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(file); + file = NULL; + return (HGResult)jmpResult; + } + +#if defined(HG_CMP_MSC) + _fseeki64(file, 0, SEEK_SET); +#else + fseeko64(file, 0, SEEK_SET); +#endif + png_init_io(png_ptr, file); + png_read_info(png_ptr, info_ptr); + + if (NULL != info) + { + info->width = info_ptr->width; + info->height = info_ptr->height; + info->bitDepth = info_ptr->bit_depth; + info->colorType = info_ptr->color_type; + info->channels = info_ptr->channels; + info->filterType = info_ptr->filter_type; + info->InterlaceType = info_ptr->interlace_type; + info->compressionType = info_ptr->compression_type; + info->pixelDepth = info_ptr->pixel_depth; + info->physUnitType = info_ptr->phys_unit_type; + info->xPixelsPerUnit = info_ptr->x_pixels_per_unit; + info->yPixelsPerUnit = info_ptr->y_pixels_per_unit; + } + + if (NULL != image) + { + png_set_scale_16(png_ptr); + png_set_expand(png_ptr); + + png_set_interlace_handling(png_ptr); + png_read_update_info(png_ptr, info_ptr); + + buffer = (uint8_t*)malloc((uintptr_t)info_ptr->rowbytes * (uintptr_t)info_ptr->height); + if (NULL == buffer) + { + longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_OUTOFMEMORY); + } + + rowPointers = (uint8_t**)malloc(info_ptr->height * sizeof(png_bytep)); + if (NULL == rowPointers) + { + longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_OUTOFMEMORY); + } + + //#pragma omp parallel for + for (png_int_32 i = 0; i < (png_int_32)info_ptr->height; ++i) + { + rowPointers[i] = buffer + (uintptr_t)i * (uintptr_t)info_ptr->rowbytes; + } + + png_read_image(png_ptr, rowPointers); + png_read_end(png_ptr, info_ptr); + + if (0 == imgType) + { + imgType = HGBASE_IMGTYPE_RGB; + if (PNG_COLOR_TYPE_GRAY_ALPHA == info_ptr->color_type || PNG_COLOR_TYPE_RGB_ALPHA == info_ptr->color_type) + { + imgType = HGBASE_IMGTYPE_RGBA; + } + else if (PNG_COLOR_TYPE_GRAY == info_ptr->color_type) + { + imgType = HGBASE_IMGTYPE_GRAY; + } + } + + if (imgOrigin == 0) + { + imgOrigin = HGBASE_IMGORIGIN_TOP; + } + + HGResult ret = HGBase_CreateImage(info_ptr->width, info_ptr->height, HGBASE_IMGTYPE_RGBA, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + longjmp(png_jmpbuf(png_ptr), (int)ret); + } + + if (PNG_RESOLUTION_METER == info_ptr->phys_unit_type) + { + uint32_t xDpi = (uint32_t)((double)info_ptr->x_pixels_per_unit / 39.3700787 + 0.5); + uint32_t yDpi = (uint32_t)((double)info_ptr->y_pixels_per_unit / 39.3700787 + 0.5); + HGBase_SetImageDpi(image2, xDpi, yDpi); + } + + uint8_t* data; + HGBase_GetImageData(image2, &data); + HGImageInfo imgInfo; + HGBase_GetImageInfo(image2, &imgInfo); + + if (PNG_COLOR_TYPE_GRAY == info_ptr->color_type) + { + //#pragma omp parallel for + for (png_int_32 i = 0; i < (png_int_32)info_ptr->height; i++) + { + uint8_t* pEx = rowPointers[i]; + uint8_t* pExEnd = pEx + info_ptr->width; + uint8_t* pDestEx = data + (HGSize)i * (HGSize)imgInfo.widthStep; + + while (pEx < pExEnd) + { + uint8_t v = *pEx; + *((uint32_t*)pDestEx) = (v & 0x000000FF) | ((v << 8) & 0x0000FF00) | ((v << 16) & 0x00FF0000) | 0xFF000000; + + ++pEx; + pDestEx += 4; + } + } + } + else if (PNG_COLOR_TYPE_RGB == info_ptr->color_type) + { + //#pragma omp parallel for + for (png_int_32 i = 0; i < (png_int_32)info_ptr->height; i++) + { + uint8_t* pEx = rowPointers[i]; + uint8_t* pExEnd = pEx + info_ptr->width * 3; + uint8_t* pDestEx = data + (HGSize)i * (HGSize)imgInfo.widthStep; + + while (pEx < pExEnd) + { + uint8_t r = pEx[0]; + uint8_t g = pEx[1]; + uint8_t b = pEx[2]; + *((uint32_t*)pDestEx) = (r & 0x000000FF) | ((g << 8) & 0x0000FF00) | ((b << 16) & 0x00FF0000) | 0xFF000000; + + pEx += 3; + pDestEx += 4; + } + } + } + else if (PNG_COLOR_TYPE_GRAY_ALPHA == info_ptr->color_type) + { + //#pragma omp parallel for + for (png_int_32 i = 0; i < (png_int_32)info_ptr->height; i++) + { + uint8_t* pEx = rowPointers[i]; + uint8_t* pExEnd = pEx + info_ptr->width * 2; + uint8_t* pDestEx = data + (HGSize)i * (HGSize)imgInfo.widthStep; + + while (pEx < pExEnd) + { + uint8_t v = pEx[0]; + uint8_t alpha = pEx[1]; + *((uint32_t*)pDestEx) = (v & 0x000000FF) | ((v << 8) & 0x0000FF00) | ((v << 16) & 0x00FF0000) | ((alpha << 24) & 0xFF000000); + + pEx += 2; + pDestEx += 4; + } + } + } + else + { + assert(PNG_COLOR_TYPE_RGB_ALPHA == info_ptr->color_type); + + //#pragma omp parallel for + for (png_int_32 i = 0; i < (png_int_32)info_ptr->height; i++) + { + uint8_t* pEx = rowPointers[i]; + uint8_t* pDestEx = data + (HGSize)i * (HGSize)imgInfo.widthStep; + memcpy(pDestEx, pEx, info_ptr->width * 4); + } + } + + ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); + if (HGBASE_ERR_OK != ret) + { + longjmp(png_jmpbuf(png_ptr), (int)ret); + } + } + + HGBase_DestroyImage(image2); + image2 = NULL; + free(rowPointers); + rowPointers = NULL; + free(buffer); + buffer = NULL; + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(file); + file = NULL; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SavePngImage(HGImage image, const HGPngSaveInfo* info, const HGChar* fileName) +{ + if (NULL == image || NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL != info) + { + // 判断合法性 + } + + FILE* file = fopen(fileName, "wb"); + if (NULL == file) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGImgFmt_SavePngImage: fopen fail, %s errno=%d", fileName, errno); + return HGBASE_ERR_ACCESSDENIED; + } + + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (NULL == png_ptr) + { + fclose(file); + file = NULL; + return HGIMGFMT_ERR_FAIL; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (NULL == info_ptr) + { + png_destroy_write_struct(&png_ptr, NULL); + fclose(file); + file = NULL; + return HGIMGFMT_ERR_FAIL; + } + + uint8_t** rowPointers = NULL; + + HGImage image2 = NULL; + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + + int jmpResult = setjmp(png_jmpbuf(png_ptr)); + if (0 != jmpResult) + { + HGBase_SetImageROI(image, &roi); + HGBase_DestroyImage(image2); + image2 = NULL; + free(rowPointers); + rowPointers = NULL; + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(file); + file = NULL; + return (HGResult)jmpResult; + } + + png_init_io(png_ptr, file); + + HGBase_ResetImageROI(image); + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_BGR == imgInfo.type) + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + longjmp(png_jmpbuf(png_ptr), (int)ret); + } + } + else if (HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_RGBA, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + longjmp(png_jmpbuf(png_ptr), (int)ret); + } + } + else if (HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + longjmp(png_jmpbuf(png_ptr), (int)ret); + } + } + else + { + HGResult ret = HGBase_CloneImage(image, imgInfo.type, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + longjmp(png_jmpbuf(png_ptr), (int)ret); + } + } + + HGBase_GetImageInfo(image2, &imgInfo); + uint32_t width = imgInfo.width; + uint32_t height = imgInfo.height; + uint32_t widthStep = imgInfo.widthStep; + uint32_t type = imgInfo.type; + uint32_t origin = imgInfo.origin; + + uint8_t* data; + HGBase_GetImageData(image2, &data); + + int color_type = -1; + if (HGBASE_IMGTYPE_GRAY == type) + color_type = PNG_COLOR_TYPE_GRAY; + else if (HGBASE_IMGTYPE_RGB == type) + color_type = PNG_COLOR_TYPE_RGB; + else if (HGBASE_IMGTYPE_RGBA == type) + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + assert(-1 != color_type); + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + if (NULL != info) + { + info_ptr->phys_unit_type = info->physUnitType; + info_ptr->x_pixels_per_unit = info->xPixelsPerUnit; + info_ptr->y_pixels_per_unit = info->yPixelsPerUnit; + info_ptr->valid |= PNG_INFO_pHYs; + } + else + { + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(image2, &xDpi, &yDpi); + info_ptr->phys_unit_type = PNG_RESOLUTION_METER; + info_ptr->x_pixels_per_unit = (uint32_t)((double)xDpi * 39.3700787 + 0.5); + info_ptr->y_pixels_per_unit = (uint32_t)((double)yDpi * 39.3700787 + 0.5); + info_ptr->valid |= PNG_INFO_pHYs; + } + + png_write_info(png_ptr, info_ptr); + + rowPointers = (uint8_t**)malloc(height * sizeof(png_bytep)); + if (NULL == rowPointers) + { + longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_OUTOFMEMORY); + } + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)height; ++i) + { + rowPointers[i] = data + (HGSize)i * (HGSize)widthStep; + } + + png_write_image(png_ptr, rowPointers); + png_write_end(png_ptr, info_ptr); + + HGBase_SetImageROI(image, &roi); + HGBase_DestroyImage(image2); + image2 = NULL; + free(rowPointers); + rowPointers = NULL; + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(file); + file = NULL; + return HGBASE_ERR_OK; +} \ No newline at end of file diff --git a/app/modules/imgfmt/HGPng.h b/app/modules/imgfmt/HGPng.h new file mode 100644 index 0000000..c040913 --- /dev/null +++ b/app/modules/imgfmt/HGPng.h @@ -0,0 +1,65 @@ +#ifndef __HGPNG_H__ +#define __HGPNG_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +/* */ +#define HGIMGFMT_PNGCLRTYPE_GRAY 0L +#define HGIMGFMT_PNGCLRTYPE_PALETTE (1L | 2L) +#define HGIMGFMT_PNGCLRTYPE_RGB 2L +#define HGIMGFMT_PNGCLRTYPE_RGB_ALPHA (2L | 4L) +#define HGIMGFMT_PNGCLRTYPE_GRAY_ALPHA 4L + +/* */ +#define HGIMGFMT_PNGFILTERTYPE_BASE 0L +/* */ +#define HGIMGFMT_PNGINTERLACE_NONE 0L +#define HGIMGFMT_PNGINTERLACE_ADAM7 1L +#define HGIMGFMT_PNGINTERLACE_LAST 2L +/* */ +#define HGIMGFMT_PNGCOMPTYPE_BASE 0L + +/* 分辨率单位 */ +#define HGIMGFMT_PNGPHYSUNIT_UNKNOWN 0L +#define HGIMGFMT_PNGPHYSUNIT_METER 1L +#define HGIMGFMT_PNGPHYSUNIT_LAST 2L + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGByte bitDepth; /* 每通道的比特数 */ + HGByte colorType; /* 色彩类型, 见HGIMGFMT_PNGCLRTYPE_* */ + HGByte channels; /* 通道数 */ + HGByte filterType; /* 见HGIMGFMT_PNGFILTERTYPE_* */ + HGByte InterlaceType; /* 见HGIMGFMT_PNGINTERLACE_* */ + HGByte compressionType; /* 见HGIMGFMT_PNGCOMPTYPE_* */ + HGByte pixelDepth; /* 每像素的比特数 */ + HGByte physUnitType; /* 分辨率单位, 见HGIMGFMT_PNGPHYSUNIT_* */ + HGUInt xPixelsPerUnit; /* 分辨率x */ + HGUInt yPixelsPerUnit; /* 分辨率y */ +}HGPngLoadInfo; + +typedef struct +{ + HGByte physUnitType; /* 分辨率单位, 见HGIMGFMT_PNGPHYSUNIT_* */ + HGUInt xPixelsPerUnit; /* 分辨率x */ + HGUInt yPixelsPerUnit; /* 分辨率y */ +}HGPngSaveInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckPngFile(const HGChar* fileName, HGBool* isPng); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadPngImage(const HGChar* fileName, HGPngLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_SavePngImage(HGImage image, const HGPngSaveInfo* info, const HGChar* fileName); + +#endif /* __HGPNG_H__ */ \ No newline at end of file diff --git a/app/modules/imgfmt/HGPnm.cpp b/app/modules/imgfmt/HGPnm.cpp new file mode 100644 index 0000000..6f6f09c --- /dev/null +++ b/app/modules/imgfmt/HGPnm.cpp @@ -0,0 +1,732 @@ +#include "HGPnm.h" +#include "../base/HGInc.h" +#include "../base/HGInfo.h" +#include +#include + +static inline HGByte GetBit(const HGByte* data, HGUInt index) +{ + HGUInt byteIndex = index / 8; + HGUInt bitIndex = index % 8; + return (data[byteIndex] >> (7 - bitIndex)) & 0x01; +} + +static inline void SetBit(HGByte* data, HGUInt index, HGByte value) +{ + assert(0 == value || 1 == value); + HGUInt byteIndex = index / 8; + HGUInt bitIndex = index % 8; + if (1 == value) + data[byteIndex] |= (1 << (7 - bitIndex)); + else + data[byteIndex] &= ~(1 << (7 - bitIndex)); +} + +static inline HGUInt MyAtoi(const HGChar* c) +{ + HGUInt value = 0; + + const HGChar* p = c; + while (0 != *p) + { + value *= 10; + value += (HGUInt)(*p - '0'); + p++; + } + + return value; +} + +HGResult HGAPI HGImgFmt_CheckPnmFile(const HGChar* fileName, HGBool* isPnm) +{ + if (NULL == fileName || NULL == isPnm) + { + return HGBASE_ERR_INVALIDARG; + } + + HGPnmLoadInfo info; + HGResult ret = HGImgFmt_LoadPnmImage(fileName, &info, 0, 0, NULL); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + *isPnm = HGTRUE; + return ret; +} + +HGResult HGAPI HGImgFmt_GetPnmTypeFromFileName(const HGChar* fileName, HGUInt* pnmType) +{ + if (NULL == fileName || NULL == pnmType) + { + return HGBASE_ERR_INVALIDARG; + } + + const char* p = strrchr(fileName, '.'); + if (NULL == p) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + if (0 == _stricmp(p, ".pbm")) + { + *pnmType = HGIMGFMT_PNMTYPE_BINARY_BINARY; + return HGBASE_ERR_OK; + } + + if (0 == _stricmp(p, ".pgm")) + { + *pnmType = HGIMGFMT_PNMTYPE_GRAY_BINARY; + return HGBASE_ERR_OK; + } + + if (0 == _stricmp(p, ".ppm")) + { + *pnmType = HGIMGFMT_PNMTYPE_RGB_BINARY; + return HGBASE_ERR_OK; + } +#else + if (0 == strcasecmp(p, ".pbm")) + { + *pnmType = HGIMGFMT_PNMTYPE_BINARY_BINARY; + return HGBASE_ERR_OK; + } + + if (0 == strcasecmp(p, ".pgm")) + { + *pnmType = HGIMGFMT_PNMTYPE_GRAY_BINARY; + return HGBASE_ERR_OK; + } + + if (0 == strcasecmp(p, ".ppm")) + { + *pnmType = HGIMGFMT_PNMTYPE_RGB_BINARY; + return HGBASE_ERR_OK; + } +#endif + + return HGBASE_ERR_FAIL; +} + +static HGResult PnmLoadInfo(FILE* file, HGUInt pnmType, HGUInt *width, HGUInt *height, HGUInt *maxColor) +{ + assert(NULL != file && NULL != width && NULL != height && NULL != maxColor); + + bool getWidth = false; + bool getHeight = false; + bool getMaxColor = false; + char buf[256]; + int bufLen = 0; + + while (1) + { + HGByte c = 0; + if (1 != fread(&c, 1, 1, file)) + { + return HGBASE_ERR_FILEERROR; + } + + if (c == '#' || c == '\n' || c == '\r' || c == '\t' || c == ' ') + { + if (0 != bufLen) + { + buf[bufLen] = 0; + + if (!getWidth) + { + *width = MyAtoi(buf); + if (*width == 0) + return HGBASE_ERR_FILEERROR; + getWidth = true; + } + else if (!getHeight) + { + *height = MyAtoi(buf); + if (*height == 0) + return HGBASE_ERR_FILEERROR; + getHeight = true; + } + else if (!getMaxColor) + { + *maxColor = MyAtoi(buf); + if (*maxColor == 0) + return HGBASE_ERR_FILEERROR; + getMaxColor = true; + } + + bufLen = 0; + } + + if (c == '#') + { + while (c != '\n') + { + if (1 != fread(&c, 1, 1, file)) + { + return HGBASE_ERR_FILEERROR; + } + } + } + } + else if (c >= '0' && c <= '9') + { + buf[bufLen] = c; + ++bufLen; + } + else + { + return HGBASE_ERR_FILEERROR; + } + + if (pnmType != HGIMGFMT_PNMTYPE_BINARY_ASCII && pnmType != HGIMGFMT_PNMTYPE_BINARY_BINARY) + { + if (getMaxColor) + { + break; + } + } + else + { + if (getHeight) + { + break; + } + } + } + + return HGBASE_ERR_OK; +} + +static HGResult PnmLoadImage(FILE* file, HGUInt pnmType, HGPnmLoadInfo* info, HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + HGUInt width = 0, height = 0, maxColor = 0; + HGResult ret = PnmLoadInfo(file, pnmType, &width, &height, &maxColor); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (pnmType != HGIMGFMT_PNMTYPE_BINARY_ASCII && pnmType != HGIMGFMT_PNMTYPE_BINARY_BINARY) + { + if (maxColor != 255) + return HGBASE_ERR_FILEERROR; + } + else + { + maxColor = 1; + } + + if (NULL != info) + { + info->width = width; + info->height = height; + info->type = pnmType; + } + + if (NULL != image) + { + if (imgType == 0) + { + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII || pnmType == HGIMGFMT_PNMTYPE_BINARY_BINARY) + imgType = HGBASE_IMGTYPE_BINARY; + else if (pnmType == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmType == HGIMGFMT_PNMTYPE_GRAY_BINARY) + imgType = HGBASE_IMGTYPE_GRAY; + else if (pnmType == HGIMGFMT_PNMTYPE_RGB_ASCII || pnmType == HGIMGFMT_PNMTYPE_RGB_BINARY) + imgType = HGBASE_IMGTYPE_RGB; + } + + if (imgOrigin == 0) + { + imgOrigin = HGBASE_IMGORIGIN_TOP; + } + + HGImage image2 = NULL; + + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII || pnmType == HGIMGFMT_PNMTYPE_BINARY_BINARY) + ret = HGBase_CreateImage(width, height, HGBASE_IMGTYPE_BINARY, HGBASE_IMGORIGIN_TOP, &image2); + else if (pnmType == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmType == HGIMGFMT_PNMTYPE_GRAY_BINARY) + ret = HGBase_CreateImage(width, height, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2); + else if (pnmType == HGIMGFMT_PNMTYPE_RGB_ASCII || pnmType == HGIMGFMT_PNMTYPE_RGB_BINARY) + ret = HGBase_CreateImage(width, height, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + uint8_t* data; + HGBase_GetImageData(image2, &data); + HGImageInfo imgInfo; + HGBase_GetImageInfo(image2, &imgInfo); + + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_BINARY || pnmType == HGIMGFMT_PNMTYPE_GRAY_BINARY || pnmType == HGIMGFMT_PNMTYPE_RGB_BINARY) + { + HGUInt lineSize = ((width + 7) & ~7) >> 3; + if (pnmType == HGIMGFMT_PNMTYPE_GRAY_BINARY) + lineSize = width; + else if (pnmType == HGIMGFMT_PNMTYPE_RGB_BINARY) + lineSize = width * 3; + + for (HGUInt i = 0; i < height; ++i) + { + if (lineSize != fread(data + i * imgInfo.widthStep, 1, lineSize, file)) + { + HGBase_DestroyImage(image2); + return HGBASE_ERR_FILEERROR; + } + } + + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_BINARY) + { + HGBase_ReverseImage(image2, image2); + } + } + else if (pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII || pnmType == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmType == HGIMGFMT_PNMTYPE_RGB_ASCII) + { + HGChar readBuf[2048]; + HGUInt readBufLen = 0; + HGChar* curReadPos = readBuf; + HGChar buf[256]; + HGUInt bufLen = 0; + HGByte* p = data; + HGUInt idx = 0; + + while (1) + { + if (0 == readBufLen) + { + readBufLen = (HGUInt)fread(readBuf, 1, 2048, file); + curReadPos = readBuf; + } + + HGByte c = 0; + HGBool getChar = HGFALSE; + if (0 != readBufLen) + { + c = *curReadPos; + ++curReadPos; + --readBufLen; + getChar = HGTRUE; + } + + if (!getChar || c == '#' || c == '\n' || c == '\r' || c == '\t' || c == ' ') + { + if (0 != bufLen) + { + buf[bufLen] = 0; + HGUInt pixel = MyAtoi(buf); + if (pixel < 0 || pixel > maxColor) + { + HGBase_DestroyImage(image2); + return HGBASE_ERR_FILEERROR; + } + + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII) + SetBit(p, idx, (pixel == 0) ? 1 : 0); + else + p[idx] = (HGByte)pixel; + + HGUInt step = width; + if (pnmType == HGIMGFMT_PNMTYPE_RGB_ASCII) + step = width * 3; + + ++idx; + if (idx == step) + { + p += imgInfo.widthStep; + idx = 0; + } + + bufLen = 0; + } + + if (!getChar) + { + if (p == data + height * imgInfo.widthStep) + { + break; + } + else + { + HGBase_DestroyImage(image2); + return HGBASE_ERR_FILEERROR; + } + } + else if (c == '#') + { + while (c != '\n') + { + c = 0; + HGBool getChar = HGFALSE; + if (0 != readBufLen) + { + c = *curReadPos; + ++curReadPos; + --readBufLen; + getChar = HGTRUE; + } + + if (!getChar) + { + HGBase_DestroyImage(image2); + return HGBASE_ERR_FILEERROR; + } + } + } + } + else if (c >= '0' && c <= '9') + { + buf[bufLen] = c; + ++bufLen; + } + else + { + HGBase_DestroyImage(image2); + return HGBASE_ERR_FILEERROR; + } + + if (p == data + height * imgInfo.widthStep) + { + break; + } + } + } + + if (imgInfo.type == imgType && imgInfo.origin == imgOrigin) + { + *image = image2; + } + else + { + ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); + HGBase_DestroyImage(image2); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_LoadPnmImage(const HGChar* fileName, HGPnmLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL == image) + { + if (0 != imgType || 0 != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + else + { + if (0 != imgType && HGBASE_IMGTYPE_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType + && HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType + && HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + +#if defined(HG_CMP_MSC) + if (0 != _access(fileName, 0)) +#else + if (0 != access(fileName, 0)) +#endif + { + return HGBASE_ERR_FILENOTEXIST; + } + + FILE* file = fopen(fileName, "rb"); + if (NULL == file) + { + return HGBASE_ERR_ACCESSDENIED; + } + + HGByte magicKey[2] = {0}; + if (2 != fread(magicKey, 1, 2, file)) + { + fclose(file); + return HGBASE_ERR_FILEERROR; + } + + HGUInt pnmType = 0; + if (magicKey[0] == 'P' && (magicKey[1] == '1')) + { + pnmType = HGIMGFMT_PNMTYPE_BINARY_ASCII; + } + else if (magicKey[0] == 'P' && (magicKey[1] == '2')) + { + pnmType = HGIMGFMT_PNMTYPE_GRAY_ASCII; + } + else if (magicKey[0] == 'P' && (magicKey[1] == '3')) + { + pnmType = HGIMGFMT_PNMTYPE_RGB_ASCII; + } + else if (magicKey[0] == 'P' && (magicKey[1] == '4')) + { + pnmType = HGIMGFMT_PNMTYPE_BINARY_BINARY; + } + else if (magicKey[0] == 'P' && (magicKey[1] == '5')) + { + pnmType = HGIMGFMT_PNMTYPE_GRAY_BINARY; + } + else if (magicKey[0] == 'P' && (magicKey[1] == '6')) + { + pnmType = HGIMGFMT_PNMTYPE_RGB_BINARY; + } + + if (0 == pnmType) + { + fclose(file); + return HGBASE_ERR_FILEERROR; + } + + HGResult ret = PnmLoadImage(file, pnmType, info, imgType, imgOrigin, image); + fclose(file); + return ret; +} + +static HGResult PnmSaveImage(HGImage image, const HGChar* fileName, HGUInt pnmType) +{ + FILE* file = fopen(fileName, "wb"); + if (NULL == file) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "PnmSaveImage: fopen fail, %s errno=%d", fileName, errno); + return HGBASE_ERR_ACCESSDENIED; + } + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + + char magicKey[4] = {0}; + if (HGIMGFMT_PNMTYPE_BINARY_ASCII == pnmType) + { + strcpy(magicKey, "P1\n"); + } + else if (HGIMGFMT_PNMTYPE_GRAY_ASCII == pnmType) + { + strcpy(magicKey, "P2\n"); + } + else if (HGIMGFMT_PNMTYPE_RGB_ASCII == pnmType) + { + strcpy(magicKey, "P3\n"); + } + else if (HGIMGFMT_PNMTYPE_BINARY_BINARY == pnmType) + { + strcpy(magicKey, "P4\n"); + } + else if (HGIMGFMT_PNMTYPE_GRAY_BINARY == pnmType) + { + strcpy(magicKey, "P5\n"); + } + else if (HGIMGFMT_PNMTYPE_RGB_BINARY == pnmType) + { + strcpy(magicKey, "P6\n"); + } + + fwrite(magicKey, 1, strlen(magicKey), file); + + char width[20], height[20]; + sprintf(width, "%u\n", imgInfo.width); + sprintf(height, "%u\n", imgInfo.height); + fwrite(width, 1, strlen(width), file); + fwrite(height, 1, strlen(height), file); + + if (HGIMGFMT_PNMTYPE_BINARY_ASCII != pnmType && HGIMGFMT_PNMTYPE_BINARY_BINARY != pnmType) + { + char maxColor[] = "255\n"; + fwrite(maxColor, 1, strlen(maxColor), file); + } + + HGByte* p = data; + HGInt step = (HGInt)imgInfo.widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + { + p = data + (imgInfo.height - 1) * imgInfo.widthStep; + step = -(HGInt)imgInfo.widthStep; + } + + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_BINARY) + { + HGUInt lineSize = ((imgInfo.width + 7) & ~7) >> 3; + HGByte* buf = (HGByte*)malloc(lineSize); + if (NULL == buf) + { + fclose(file); + return HGBASE_ERR_OUTOFMEMORY; + } + + for (HGUInt i = 0; i < imgInfo.height; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + for (HGUInt j = 0; j < lineSize; ++j) + { + buf[j] = ~pEx[j]; // 黑白反色 + } + + fwrite(buf, 1, lineSize, file); + } + + free(buf); + } + else if (pnmType == HGIMGFMT_PNMTYPE_GRAY_BINARY) + { + for (HGUInt i = 0; i < imgInfo.height; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + fwrite(pEx, 1, imgInfo.width, file); + } + } + else if (pnmType == HGIMGFMT_PNMTYPE_RGB_BINARY) + { + for (HGUInt i = 0; i < imgInfo.height; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + fwrite(pEx, 1, imgInfo.width * 3, file); + } + } + else if (pnmType == HGIMGFMT_PNMTYPE_RGB_ASCII || pnmType == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII) + { + HGUInt w = imgInfo.width; + if (HGIMGFMT_PNMTYPE_RGB_ASCII == pnmType) + w = imgInfo.width * 3; + + char *buf = (char *)malloc(w * 5 + 1); + if (NULL == buf) + { + fclose(file); + return HGBASE_ERR_OUTOFMEMORY; + } + + std::string pixelStr[256]; + for (int i = 0; i < 256; ++i) + { + char str[6]; + sprintf(str, "%d", i); + pixelStr[i] = str; + } + + for (HGUInt i = 0; i < imgInfo.height; ++i) + { + int bufLen = 0; + int lineSize = 0; + + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + for (HGUInt j = 0; j < w; ++j) + { + HGUInt idx; + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII) + idx = (0 == GetBit(pEx, j) ? 1 : 0); + else + idx = pEx[j]; + + if (0 != lineSize) + { + if (lineSize + pixelStr[idx].size() + 1 > 70) + { + buf[bufLen] = '\n'; + ++bufLen; + lineSize = 0; + } + else + { + buf[bufLen] = ' '; + ++bufLen; + ++lineSize; + } + } + + strcpy(buf + bufLen, pixelStr[idx].c_str()); + bufLen += (int)pixelStr[idx].size(); + lineSize += (int)pixelStr[idx].size(); + } + + buf[bufLen] = '\n'; + ++bufLen; + lineSize = 0; + + fwrite(buf, 1, bufLen, file); + } + + free(buf); + } + + fclose(file); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SavePnmImage(HGImage image, const HGPnmSaveInfo* info, const HGChar* fileName) +{ + if (NULL == image || NULL == fileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL != info) + { + if (info->type < HGIMGFMT_PNMTYPE_BINARY_ASCII || info->type > HGIMGFMT_PNMTYPE_RGB_BINARY) + { + return HGBASE_ERR_INVALIDARG; + } + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + + HGUInt pnmType = HGIMGFMT_PNMTYPE_RGB_BINARY; + if (HGBASE_IMGTYPE_GRAY == imgInfo.type) + pnmType = HGIMGFMT_PNMTYPE_GRAY_BINARY; + else if (HGBASE_IMGTYPE_BINARY == imgInfo.type) + pnmType = HGIMGFMT_PNMTYPE_BINARY_BINARY; + + if (NULL != info) + { + pnmType = info->type; + } + else + { + HGUInt pnmType2 = 0; + HGImgFmt_GetPnmTypeFromFileName(fileName, &pnmType2); + if (0 != pnmType2) + { + pnmType = pnmType2; + } + } + + HGUInt imgType = HGBASE_IMGTYPE_RGB; + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII || pnmType == HGIMGFMT_PNMTYPE_BINARY_BINARY) + imgType = HGBASE_IMGTYPE_BINARY; + else if (pnmType == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmType == HGIMGFMT_PNMTYPE_GRAY_BINARY) + imgType = HGBASE_IMGTYPE_GRAY; + + if (imgInfo.type != imgType) + { + HGImage image2 = NULL; + HGResult ret = HGBase_CloneImage(image, imgType, HGBASE_IMGORIGIN_TOP, &image2); + if (ret != HGBASE_ERR_OK) + { + return ret; + } + + ret = PnmSaveImage(image2, fileName, pnmType); + HGBase_DestroyImage(image2); + return ret; + } + + return PnmSaveImage(image, fileName, pnmType); +} diff --git a/app/modules/imgfmt/HGPnm.h b/app/modules/imgfmt/HGPnm.h new file mode 100644 index 0000000..ee393e6 --- /dev/null +++ b/app/modules/imgfmt/HGPnm.h @@ -0,0 +1,43 @@ +#ifndef __HGPNM_H__ +#define __HGPNM_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +#define HGIMGFMT_PNMTYPE_BINARY_ASCII 1L +#define HGIMGFMT_PNMTYPE_BINARY_BINARY 2L +#define HGIMGFMT_PNMTYPE_GRAY_ASCII 3L +#define HGIMGFMT_PNMTYPE_GRAY_BINARY 4L +#define HGIMGFMT_PNMTYPE_RGB_ASCII 5L +#define HGIMGFMT_PNMTYPE_RGB_BINARY 6L + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUInt type; /* 类型 */ +}HGPnmLoadInfo; + +typedef struct +{ + HGUInt type; /* 类型 */ +}HGPnmSaveInfo; + +#pragma pack(pop) + + +HGEXPORT HGResult HGAPI HGImgFmt_CheckPnmFile(const HGChar* fileName, HGBool* isPnm); + +HGEXPORT HGResult HGAPI HGImgFmt_GetPnmTypeFromFileName(const HGChar* fileName, HGUInt* pnmType); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadPnmImage(const HGChar* fileName, HGPnmLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_SavePnmImage(HGImage image, const HGPnmSaveInfo* info, const HGChar* fileName); + +#endif // __HGPNM_H__ diff --git a/app/modules/imgfmt/HGTiff.cpp b/app/modules/imgfmt/HGTiff.cpp new file mode 100644 index 0000000..4e6a0e2 --- /dev/null +++ b/app/modules/imgfmt/HGTiff.cpp @@ -0,0 +1,414 @@ +#include "HGTiff.h" +#include "../base/HGInc.h" +#include "../base/HGInfo.h" +#include "tiffio.h" + +HGResult HGAPI HGImgFmt_CheckTiffFile(const HGChar* fileName, HGBool* isTiff) +{ + if (NULL == fileName || NULL == isTiff) + { + return HGBASE_ERR_INVALIDARG; + } + + HGTiffReader reader = NULL; + HGResult ret = HGImgFmt_OpenTiffReader(fileName, &reader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + *isTiff = HGTRUE; + HGImgFmt_CloseTiffReader(reader); + return ret; +} + +HGResult HGAPI HGImgFmt_OpenTiffReader(const HGChar* fileName, HGTiffReader* reader) +{ + if (NULL == fileName || NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + +#if defined(HG_CMP_MSC) + if (0 != _access(fileName, 0)) +#else + if (0 != access(fileName, 0)) +#endif + { + return HGBASE_ERR_FILENOTEXIST; + } + + TIFF* tif = TIFFOpen(fileName, "r"); + if (NULL == tif) + { + return HGBASE_ERR_FILEERROR; + } + + *reader = (HGTiffReader)tif; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_CloseTiffReader(HGTiffReader reader) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + TIFF* tif = (TIFF*)reader; + TIFFClose(tif); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_GetTiffPageCount(HGTiffReader reader, HGUInt* count) +{ + if (NULL == reader || NULL == count) + { + return HGBASE_ERR_INVALIDARG; + } + + TIFF* tif = (TIFF*)reader; + *count = TIFFNumberOfDirectories(tif); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_LoadImageFromTiffReader(HGTiffReader reader, HGUInt index, HGTiffLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + if (NULL == reader) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL == image) + { + if (0 != imgType || 0 != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + else + { + if (0 != imgType && HGBASE_IMGTYPE_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType + && HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType + && HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) + { + return HGBASE_ERR_INVALIDARG; + } + } + + TIFF* tif = (TIFF*)reader; + if (0 == TIFFSetDirectory(tif, index)) + { + return HGIMGFMT_ERR_FAIL; + } + + uint32 width; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + uint32 height; + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + uint16 bitsPerSample; + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); + uint16 samplesPerPixel; + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); + uint16 compression; + TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression); + + uint16 resolutionUnit; + TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resolutionUnit); + float xResolution; + TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xResolution); + float yResolution; + TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yResolution); + + if (NULL != info) + { + info->width = width; + info->height = height; + info->bitsPerSample = bitsPerSample; + info->samplesPerPixel = samplesPerPixel; + info->compression = compression; + info->resolutionUnit = resolutionUnit; + info->xResolution = xResolution; + info->yResolution = yResolution; + } + + if (NULL != image) + { + uint32* buffer = (uint32*)malloc(width * height * sizeof(uint32)); + if (NULL == buffer) + { + return HGBASE_ERR_OUTOFMEMORY; + } + + if (0 == TIFFReadRGBAImageOriented(tif, width, height, buffer, ORIENTATION_TOPLEFT)) + { + free(buffer); + buffer = NULL; + return HGIMGFMT_ERR_FAIL; + } + + if (0 == imgType) + { + imgType = HGBASE_IMGTYPE_RGB; + if (4 == samplesPerPixel) + { + imgType = HGBASE_IMGTYPE_RGBA; + } + else if (1 == samplesPerPixel) + { + if (1 == bitsPerSample) + imgType = HGBASE_IMGTYPE_BINARY; + else + imgType = HGBASE_IMGTYPE_GRAY; + } + } + + if (imgOrigin == 0) + { + imgOrigin = HGBASE_IMGORIGIN_TOP; + } + + HGImageInfo tiffImageInfo; + tiffImageInfo.width = width; + tiffImageInfo.height = height; + tiffImageInfo.type = HGBASE_IMGTYPE_RGBA; + tiffImageInfo.widthStep = width * 4; + tiffImageInfo.origin = HGBASE_IMGORIGIN_TOP; + + HGImage image2 = NULL; + HGResult ret = HGBase_CreateImageWithData((HGByte*)buffer, &tiffImageInfo, &image2); + if (HGBASE_ERR_OK != ret) + { + free(buffer); + buffer = NULL; + return ret; + } + + if (RESUNIT_INCH == resolutionUnit) + { + uint32_t xDpi = (uint32_t)(xResolution + 0.5f); + uint32_t yDpi = (uint32_t)(yResolution + 0.5f); + HGBase_SetImageDpi(image2, xDpi, yDpi); + } + else if (RESUNIT_CENTIMETER == resolutionUnit) + { + uint32_t xDpi = (uint32_t)(xResolution / 0.393700787402 + 0.5); + uint32_t yDpi = (uint32_t)(yResolution / 0.393700787402 + 0.5); + HGBase_SetImageDpi(image2, xDpi, yDpi); + } + + ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); + HGBase_DestroyImage(image2); + if (HGBASE_ERR_OK != ret) + { + free(buffer); + buffer = NULL; + return ret; + } + + free(buffer); + buffer = NULL; + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_LoadTiffImage(const HGChar* fileName, HGTiffLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image) +{ + HGTiffReader reader = NULL; + HGResult ret = HGImgFmt_OpenTiffReader(fileName, &reader); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGImgFmt_LoadImageFromTiffReader(reader, 0, info, imgType, imgOrigin, image); + HGImgFmt_CloseTiffReader(reader); + return ret; +} + +HGResult HGAPI HGImgFmt_OpenTiffWriter(const HGChar* fileName, HGTiffWriter* writer) +{ + if (NULL == fileName || NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + TIFF* tif = TIFFOpen(fileName, "w"); + if (NULL == tif) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGImgFmt_OpenTiffWriter: TIFFOpen fail, %s", fileName); + return HGBASE_ERR_ACCESSDENIED; + } + + *writer = (HGTiffWriter)tif; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_CloseTiffWriter(HGTiffWriter writer) +{ + if (NULL == writer) + { + return HGBASE_ERR_INVALIDARG; + } + + TIFF* tif = (TIFF*)writer; + TIFFClose(tif); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveImageToTiffWriter(HGTiffWriter writer, HGImage image, const HGTiffSaveInfo* info) +{ + if (NULL == writer || NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL != info) + { + // 判断合法性 + } + + HGImage image2 = NULL; + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + + HGBase_ResetImageROI(image); + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_BGR == imgInfo.type) + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + HGBase_SetImageROI(image, &roi); + return ret; + } + } + else if (HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_RGBA, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + HGBase_SetImageROI(image, &roi); + return ret; + } + } + else + { + HGResult ret = HGBase_CloneImage(image, imgInfo.type, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + { + HGBase_SetImageROI(image, &roi); + return ret; + } + } + + HGBase_GetImageInfo(image2, &imgInfo); + uint32_t width = imgInfo.width; + uint32_t height = imgInfo.height; + uint32_t widthStep = imgInfo.widthStep; + uint32_t type = imgInfo.type; + uint32_t origin = imgInfo.origin; + uint8_t* data; + HGBase_GetImageData(image2, &data); + + uint8 samplesPerPixel = 0; + uint8 bitsPerSample = 0; + if (HGBASE_IMGTYPE_BINARY == type) + { + samplesPerPixel = 1; + bitsPerSample = 1; + } + else if (HGBASE_IMGTYPE_GRAY == type) + { + samplesPerPixel = 1; + bitsPerSample = 8; + } + else if (HGBASE_IMGTYPE_RGB == type) + { + samplesPerPixel = 3; + bitsPerSample = 8; + } + else if (HGBASE_IMGTYPE_RGBA == type) + { + samplesPerPixel = 4; + bitsPerSample = 8; + } + assert(0 != samplesPerPixel && 0 != bitsPerSample); + + TIFF* tif = (TIFF*)writer; + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitsPerSample); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, (1 == samplesPerPixel) ? PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, height); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + + if (NULL != info) + { + if ((HGBASE_IMGTYPE_BINARY == type && HGIMGFMT_TIFFCOMP_JPEG == info->compression) + || (HGBASE_IMGTYPE_BINARY != type && HGIMGFMT_TIFFCOMP_CCITTFAX4 == info->compression)) + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW); + else + TIFFSetField(tif, TIFFTAG_COMPRESSION, info->compression); + + TIFFSetField(tif, TIFFTAG_JPEGQUALITY, info->jpegQuality); + TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, info->resolutionUnit); + TIFFSetField(tif, TIFFTAG_XRESOLUTION, info->xResolution); + TIFFSetField(tif, TIFFTAG_YRESOLUTION, info->yResolution); + + if (HGIMGFMT_TIFFCOMP_JPEG == info->compression && HGBASE_IMGTYPE_RGB == type) + { + TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR); + } + } + else + { + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(image, &xDpi, &yDpi); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW); + TIFFSetField(tif, TIFFTAG_JPEGQUALITY, 80); + TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); + TIFFSetField(tif, TIFFTAG_XRESOLUTION, xDpi); + TIFFSetField(tif, TIFFTAG_YRESOLUTION, yDpi); + } + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)height; ++i) + { + uint8_t* pEx = data + (HGSize)i * (HGSize)widthStep; + TIFFWriteScanline(tif, pEx, i, 0); + } + + HGBase_SetImageROI(image, &roi); + HGBase_DestroyImage(image2); + image2 = NULL; + TIFFWriteDirectory(tif); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgFmt_SaveTiffImage(HGImage image, const HGTiffSaveInfo* info, const HGChar* fileName) +{ + HGTiffWriter writer = NULL; + HGResult ret = HGImgFmt_OpenTiffWriter(fileName, &writer); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = HGImgFmt_SaveImageToTiffWriter(writer, image, info); + HGImgFmt_CloseTiffWriter(writer); + return ret; +} \ No newline at end of file diff --git a/app/modules/imgfmt/HGTiff.h b/app/modules/imgfmt/HGTiff.h new file mode 100644 index 0000000..324a19e --- /dev/null +++ b/app/modules/imgfmt/HGTiff.h @@ -0,0 +1,71 @@ +#ifndef __HGTIFF_H__ +#define __HGTIFF_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +HG_DECLARE_HANDLE(HGTiffReader); +HG_DECLARE_HANDLE(HGTiffWriter); + +/* 压缩方式 */ +#define HGIMGFMT_TIFFCOMP_NONE 1L +#define HGIMGFMT_TIFFCOMP_CCITTFAX4 4L +#define HGIMGFMT_TIFFCOMP_LZW 5L +#define HGIMGFMT_TIFFCOMP_JPEG 7L + +/* 分辨率单位 */ +#define HGIMGFMT_TIFFRESUNIT_NONE 1L +#define HGIMGFMT_TIFFRESUNIT_INCH 2L /* 英寸 */ +#define HGIMGFMT_TIFFRESUNIT_CENTIMETER 3L /* 厘米 */ + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUShort bitsPerSample; /* 每个采样的比特数 */ + HGUShort samplesPerPixel; /* 每个像素的采样数 */ + HGUShort compression; /* 压缩方式, 见HGIMGFMT_TIFFCOMP_* */ + HGUShort resolutionUnit; /* 分辨率单位, 见HGIMGFMT_TIFFRESUNIT_* */ + HGFloat xResolution; /* 分辨率x值 */ + HGFloat yResolution; /* 分辨率y值 */ +}HGTiffLoadInfo; + +typedef struct +{ + HGUInt compression; /* 压缩方式, 见HGIMGFMT_TIFFCOMP_* */ + HGUInt jpegQuality; /* jpeg压缩质量, 0-100 */ + HGUShort resolutionUnit; /* 分辨率单位, 见HGIMGFMT_TIFFRESUNIT_* */ + HGFloat xResolution; /* 分辨率x值 */ + HGFloat yResolution; /* 分辨率y值 */ +}HGTiffSaveInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckTiffFile(const HGChar* fileName, HGBool* isTiff); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenTiffReader(const HGChar* fileName, HGTiffReader* reader); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseTiffReader(HGTiffReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_GetTiffPageCount(HGTiffReader reader, HGUInt* count); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromTiffReader(HGTiffReader reader, HGUInt index, HGTiffLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadTiffImage(const HGChar* fileName, HGTiffLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenTiffWriter(const HGChar* fileName, HGTiffWriter* writer); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseTiffWriter(HGTiffWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveImageToTiffWriter(HGTiffWriter writer, HGImage image, const HGTiffSaveInfo* info); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveTiffImage(HGImage image, const HGTiffSaveInfo* info, const HGChar* fileName); + +#endif /* __HGTIFF_H__ */ \ No newline at end of file diff --git a/app/modules/imgproc/CvxText.cpp b/app/modules/imgproc/CvxText.cpp new file mode 100644 index 0000000..0c6c65d --- /dev/null +++ b/app/modules/imgproc/CvxText.cpp @@ -0,0 +1,463 @@ +#include "CvxText.hpp" +#include "../base/HGDef.h" +#include "../base/HGInc.h" +#include + +CvxText::CvxText() +{ + m_library = NULL; + m_face = NULL; +} + +CvxText::~CvxText() +{ + Destroy(); +} + +HGResult CvxText::Create(const HGChar* fontPath) +{ + if (NULL != m_face) + { + return HGBASE_ERR_FAIL; + } + + FT_Init_FreeType(&m_library); + if (NULL == m_library) + { + return HGBASE_ERR_FAIL; + } + + FT_New_Face(m_library, fontPath, 0, &m_face); + if (NULL == m_face) + { + FT_Done_FreeType(m_library); + m_library = NULL; + return HGBASE_ERR_FAIL; + } + + return HGBASE_ERR_OK; +} + +HGResult CvxText::Destroy() +{ + if (NULL == m_face) + { + return HGBASE_ERR_FAIL; + } + + FT_Done_Face(m_face); + m_face = NULL; + FT_Done_FreeType(m_library); + m_library = NULL; + return HGBASE_ERR_OK; +} + +#if defined(HG_CMP_MSC) +static WCHAR *GetUnicodeStr(const char *text) +{ + int len = ::MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0); + WCHAR *pUnicode = new WCHAR [len]; + ::MultiByteToWideChar(CP_ACP, 0, text, -1, pUnicode, len); + return pUnicode; +} +#else +static uint16_t *GetUnicodeStr(const char *text) +{ + if (0 == *text) + { + uint16_t *pUnicode = new uint16_t [1]; + *pUnicode = 0; + return pUnicode; + } + + uint16_t *pUnicode = new uint16_t [strlen(text) + 2]; + memset(pUnicode, 0, sizeof(uint16_t) * (strlen(text) + 2)); + + iconv_t cd = iconv_open("UNICODE//IGNORE", "UTF-8"); + if ((iconv_t)-1 != cd) + { + char *inbuf = (char *)text; + size_t inbytes = strlen(text); + char *outbuf = (char *)pUnicode; + size_t outsize = sizeof(uint16_t) * (strlen(text) + 1); + + iconv(cd, &inbuf, &inbytes, &outbuf, &outsize); + iconv_close(cd); + } + + return pUnicode; +} +#endif + +HGResult CvxText::DrawString(HGImage image, const HGChar* text, HGColor color, HGUInt posType, HGInt locationX, HGInt locationY, + HGUInt fontSize, HGBool bold, HGBool underline, HGBool italic, HGBool strikeout) +{ + if (NULL == m_face) + { + return HGBASE_ERR_FAIL; + } + + assert(NULL != image); + assert(NULL != text && '\0' != *text); + assert(posType >= HGIMGPROC_WMPOSTYPE_LEFT && posType <= HGIMGPROC_WMPOSTYPE_LOCATION); + assert(0 != fontSize); + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = DrawString(imageTmp, text, color, posType, locationX, locationY, fontSize, bold, underline, italic, strikeout); + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGUInt width, height; + std::vector vPos; + GetStringLocation(text, fontSize, bold, underline, italic, strikeout, width, height, vPos); + + if (HGIMGPROC_WMPOSTYPE_LOCATION == posType) + { +#if defined(HG_CMP_MSC) + WCHAR* pUnicode = GetUnicodeStr(text); +#else + uint16_t* pUnicode = GetUnicodeStr(text); + uint16_t* pUnicodeEx = pUnicode + 1; +#endif + + int i = 0; +#if defined(HG_CMP_MSC) + while ('\0' != pUnicode[i]) +#else + while ('\0' != pUnicodeEx[i]) +#endif + { +#if defined(HG_CMP_MSC) + DrawChar(image, pUnicode[i], color, locationX + vPos[i].left, locationY + vPos[i].top, fontSize, bold, italic); +#else + DrawChar(image, pUnicodeEx[i], color, locationX + vPos[i].left, locationY + vPos[i].top, fontSize, bold, italic); +#endif + ++i; + } + + delete[] pUnicode; + + if (underline) + { + HGImgProc_ImageDrawLine(image, locationX, locationY + height - 1, + locationX + width, locationY + height - 1, color, 1, HGIMGPROC_LINETYPE_SOLID); + } + + if (strikeout) + { + if (underline) + HGImgProc_ImageDrawLine(image, locationX, locationY + (height - 1) / 2, + locationX + width, locationY + (height - 1) / 2, color, 1, HGIMGPROC_LINETYPE_SOLID); + else + HGImgProc_ImageDrawLine(image, locationX, locationY + height / 2, + locationX + width, locationY + height / 2, color, 1, HGIMGPROC_LINETYPE_SOLID); + } + + return HGBASE_ERR_OK; + } + + HGImageRoi imgRoi; + HGBase_GetImageROI(image, &imgRoi); + HGInt roiWidth = imgRoi.right - imgRoi.left; + HGInt roiHeight = imgRoi.bottom - imgRoi.top; + + HGInt x, y; + if (HGIMGPROC_WMPOSTYPE_LEFT == posType) + { + x = 0; + y = (roiHeight - height) / 2; + } + else if (HGIMGPROC_WMPOSTYPE_TOP == posType) + { + x = (roiWidth - width) / 2; + y = 0; + } + else if (HGIMGPROC_WMPOSTYPE_RIGHT == posType) + { + x = roiWidth - width; + y = (roiHeight - height) / 2; + } + else if (HGIMGPROC_WMPOSTYPE_BOTTOM == posType) + { + x = (roiWidth - width) / 2; + y = roiHeight - height; + } + else if (HGIMGPROC_WMPOSTYPE_LEFTTOP == posType) + { + x = 0; + y = 0; + } + else if (HGIMGPROC_WMPOSTYPE_RIGHTTOP == posType) + { + x = roiWidth - width; + y = 0; + } + else if (HGIMGPROC_WMPOSTYPE_LEFTBOTTOM == posType) + { + x = 0; + y = roiHeight - height; + } + else if (HGIMGPROC_WMPOSTYPE_RIGHTBOTTOM == posType) + { + x = roiWidth - width; + y = roiHeight - height; + } + else + { + x = (roiWidth - width) / 2; + y = (roiHeight - height) / 2; + } + + return DrawString(image, text, color, HGIMGPROC_WMPOSTYPE_LOCATION, x, y, fontSize, bold, underline, italic, strikeout); +} + +void CvxText::MeasureChar(HGUInt wc, HGUInt fontSize, HGBool bold, HGBool italic, FT_BBox& acbox) +{ + assert(NULL != m_face); + assert(0 != fontSize); + + FT_Set_Pixel_Sizes(m_face, fontSize, fontSize); + FT_UInt glyph_index = FT_Get_Char_Index(m_face, wc); + FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT); + + if (bold) + { + if (m_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) + { + FT_Outline_Embolden(&m_face->glyph->outline, fontSize * 2); + } + } + + if (italic) + { + if (m_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) + { + FT_Matrix matrix; + matrix.xx = 0x10000L; + matrix.xy = 0.4f * 0x10000L; + matrix.yx = 0; + matrix.yy = 0x10000L; + FT_Outline_Transform(&m_face->glyph->outline, &matrix); + } + } + + if (m_face->glyph->format != FT_GLYPH_FORMAT_BITMAP) + { + FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_NORMAL); + } + + FT_Glyph glyph; + FT_Get_Glyph(m_face->glyph, &glyph); + FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &acbox); +} + +void CvxText::GetStringLocation(const HGChar* text, HGUInt fontSize, HGBool bold, HGBool underline, HGBool italic, HGBool strikeout, + HGUInt& width, HGUInt& height, std::vector &vPos) +{ + assert(NULL != text && '\0' != *text); + assert(0 != fontSize); + + width = 0; + height = 0; + vPos.clear(); + +#if defined(HG_CMP_MSC) + WCHAR* pUnicode = GetUnicodeStr(text); +#else + uint16_t* pUnicode = GetUnicodeStr(text); + uint16_t* pUnicodeEx = pUnicode + 1; +#endif + + HGInt origin = 0; + HGInt minY = INT_MAX, maxY = INT_MIN; + + int i = 0; +#if defined(HG_CMP_MSC) + while ('\0' != pUnicode[i]) +#else + while ('\0' != pUnicodeEx[i]) +#endif + { + FT_BBox acbox; +#if defined(HG_CMP_MSC) + MeasureChar(pUnicode[i], fontSize, bold, italic, acbox); +#else + MeasureChar(pUnicodeEx[i], fontSize, bold, italic, acbox); +#endif + + HGRect pos; + pos.left = origin + acbox.xMin; + pos.right = origin + acbox.xMax; + pos.top = -acbox.yMax; + pos.bottom = -acbox.yMin; + vPos.push_back(pos); + +#if defined(HG_CMP_MSC) + if (pUnicode[i] < 255 && (!isprint((int)pUnicode[i]) || isspace((int)pUnicode[i]))) +#else + if (pUnicodeEx[i] < 255 && (!isprint((int)pUnicodeEx[i]) || isspace((int)pUnicodeEx[i]))) +#endif + { + origin += fontSize / 2; + } + else + { + origin += (acbox.xMax + acbox.xMin); + } + + if (acbox.yMin < minY) + minY = acbox.yMin; + if (acbox.yMax > maxY) + maxY = acbox.yMax; + + ++i; + } + + delete[] pUnicode; + + width = origin; + height = (maxY - minY); + if (underline) + ++height; + + for (int i = 0; i < (int)vPos.size(); ++i) + { + vPos[i].top += maxY; + vPos[i].bottom += maxY; + } +} + +void CvxText::DrawChar(HGImage image, HGUInt wc, HGColor color, HGInt x, HGInt y, HGUInt fontSize, HGBool bold, HGBool italic) +{ + assert(NULL != m_face); + assert(NULL != image); + assert(0 != fontSize); + + FT_Set_Pixel_Sizes(m_face, fontSize, fontSize); + FT_UInt glyph_index = FT_Get_Char_Index(m_face, wc); + FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT); + + if (bold) + { + if (m_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) + { + FT_Outline_Embolden(&m_face->glyph->outline, fontSize * 2); + } + } + + if (italic) + { + if (m_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) + { + FT_Matrix matrix; + matrix.xx = 0x10000L; + matrix.xy = 0.4f * 0x10000L; + matrix.yx = 0; + matrix.yy = 0x10000L; + FT_Outline_Transform(&m_face->glyph->outline, &matrix); + } + } + + if (m_face->glyph->format != FT_GLYPH_FORMAT_BITMAP) + { + FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_NORMAL); + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + uint32_t imgWidth = imgInfo.width; + uint32_t imgHeight = imgInfo.height; + uint32_t imgWidthStep = imgInfo.widthStep; + uint32_t imgType = imgInfo.type; + + uint8_t *imgData; + HGBase_GetImageData(image, &imgData); + + int32_t imgChannel = 0; + if (HGBASE_IMGTYPE_GRAY == imgType) + imgChannel = 1; + else if (HGBASE_IMGTYPE_RGB == imgType || HGBASE_IMGTYPE_BGR == imgType) + imgChannel = 3; + else if (HGBASE_IMGTYPE_RGBA == imgType || HGBASE_IMGTYPE_BGRA == imgType) + imgChannel = 4; + assert(0 != imgChannel); + + HGImageRoi imgRoi; + HGBase_GetImageROI(image, &imgRoi); + uint32_t imgLeft = imgRoi.left; + uint32_t imgTop = imgRoi.top; + uint32_t imgRight = imgRoi.right; + uint32_t imgBottom = imgRoi.bottom; + + for (unsigned int i = 0; i < m_face->glyph->bitmap.rows; ++i) + { + for (unsigned int j = 0; j < m_face->glyph->bitmap.width; ++j) + { + int32_t xOffset = (int32_t)imgLeft + x + (int32_t)j; + int32_t yOffset = (int32_t)imgTop + y + (int32_t)i; + + if (xOffset >= (int32_t)imgLeft && xOffset < (int32_t)imgRight + && yOffset >= (int32_t)imgTop && yOffset < (int32_t)imgBottom) + { + uint8_t *p = m_face->glyph->bitmap.buffer + m_face->glyph->bitmap.pitch * i + j; + int32_t opacity = HG_GETCOLOR_A(color) * (*p) / 255; + + uint8_t *pEx = imgData + yOffset * imgWidthStep + xOffset * imgChannel; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + pEx = imgData + (imgHeight - yOffset - 1) * imgWidthStep + xOffset * imgChannel; + + if (HGBASE_IMGTYPE_RGB == imgType || HGBASE_IMGTYPE_RGBA == imgType) + { + int32_t v0 = HG_GETCOLOR_R(color); + int32_t vDest0 = pEx[0]; + int32_t value0 = (v0 - vDest0) * opacity; + pEx[0] = (uint8_t)(vDest0 + (((value0 << 8) + value0) >> 16)); + + int32_t v1 = HG_GETCOLOR_G(color); + int32_t vDest1 = pEx[1]; + int32_t value1 = (v1 - vDest1) * opacity; + pEx[1] = (uint8_t)(vDest1 + (((value1 << 8) + value1) >> 16)); + + int32_t v2 = HG_GETCOLOR_B(color); + int32_t vDest2 = pEx[2]; + int32_t value2 = (v2 - vDest2) * opacity; + pEx[2] = (uint8_t)(vDest2 + (((value2 << 8) + value2) >> 16)); + } + else if (HGBASE_IMGTYPE_BGR == imgType || HGBASE_IMGTYPE_BGRA == imgType) + { + int32_t v0 = HG_GETCOLOR_B(color); + int32_t vDest0 = pEx[0]; + int32_t value0 = (v0 - vDest0) * opacity; + pEx[0] = (uint8_t)(vDest0 + (((value0 << 8) + value0) >> 16)); + + int32_t v1 = HG_GETCOLOR_G(color); + int32_t vDest1 = pEx[1]; + int32_t value1 = (v1 - vDest1) * opacity; + pEx[1] = (uint8_t)(vDest1 + (((value1 << 8) + value1) >> 16)); + + int32_t v2 = HG_GETCOLOR_R(color); + int32_t vDest2 = pEx[2]; + int32_t value2 = (v2 - vDest2) * opacity; + pEx[2] = (uint8_t)(vDest2 + (((value2 << 8) + value2) >> 16)); + } + else + { + int32_t v = (HG_GETCOLOR_R(color) * 76 + HG_GETCOLOR_G(color) * 150 + HG_GETCOLOR_B(color) * 30) >> 8; + int32_t vDest = *pEx; + int32_t value = (v - vDest) * opacity; + *pEx = (uint8_t)(vDest + (((value << 8) + value) >> 16)); + } + } + } + } +} diff --git a/app/modules/imgproc/CvxText.hpp b/app/modules/imgproc/CvxText.hpp new file mode 100644 index 0000000..ba23166 --- /dev/null +++ b/app/modules/imgproc/CvxText.hpp @@ -0,0 +1,34 @@ +#ifndef __CVXTEXT_H__ +#define __CVXTEXT_H__ + +#include "HGImgProc.h" +#include +#include +#include +#include +#include +#include + +class CvxText +{ +public: + CvxText(); + ~CvxText(); + + HGResult Create(const HGChar *fontPath); + HGResult Destroy(); + HGResult DrawString(HGImage image, const HGChar* text, HGColor color, HGUInt posType, HGInt locationX, HGInt locationY, + HGUInt fontSize, HGBool bold, HGBool underline, HGBool italic, HGBool strikeout); + +private: + void MeasureChar(HGUInt wc, HGUInt fontSize, HGBool bold, HGBool italic, FT_BBox& acbox); + void GetStringLocation(const HGChar* text, HGUInt fontSize, HGBool bold, HGBool underline, HGBool italic, HGBool strikeout, + HGUInt &width, HGUInt &height, std::vector &vPos); + void DrawChar(HGImage image, HGUInt wc, HGColor color, HGInt x, HGInt y, HGUInt fontSize, HGBool bold, HGBool italic); + +private: + FT_Library m_library; + FT_Face m_face; +}; + +#endif /* __CVXTEXT_H__ */ diff --git a/app/modules/imgproc/HGImgProc.cpp b/app/modules/imgproc/HGImgProc.cpp new file mode 100644 index 0000000..bd6ee20 --- /dev/null +++ b/app/modules/imgproc/HGImgProc.cpp @@ -0,0 +1,1684 @@ +#include "HGImgProc.h" +#include "./ImageProcess/ImageApplyAdjustColors.h" +#include "./ImageProcess/ImageApplyAutoCrop.h" +#include "./ImageProcess/ImageApplyDiscardBlank.h" +#include "./ImageProcess/ImageApplyBWBinaray.h" +#include "./ImageProcess/ImageApplyChannel.h" +#include "./ImageProcess/ImageApplyColorRecognition.h" +#include "./ImageProcess/ImageApplyDispersion.h" +#include "./ImageProcess/ImageApplyFadeBackGroundColor.h" +#include "./ImageProcess/ImageApplyFilter.h" +#include "./ImageProcess/ImageApplyOutHole.h" +#include "./ImageProcess/ImageApplyHSVCorrect.h" +#include "CvxText.hpp" +#include "../base/HGInc.h" +#include "../base/HGUtility.h" + +HGResult HGAPI HGImgProc_ResizeImage(HGImage image, HGImage destImage, HGUInt interp) +{ + if (NULL == image || NULL == destImage || image == destImage) + { + return HGBASE_ERR_INVALIDARG; + } + + if (HGIMGPROC_INTERPOTYPE_NN != interp && HGIMGPROC_INTERPOTYPE_LINEAR != interp) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + HGImageInfo destImgInfo; + HGBase_GetImageInfo(destImage, &destImgInfo); + + uint32_t type = imgInfo.type; + uint32_t destType = destImgInfo.type; + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + HGByte* destData = NULL; + HGBase_GetImageData(destImage, &destData); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGImageRoi destRoi; + HGBase_GetImageROI(destImage, &destRoi); + + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + HGUInt destRoiWidth = destRoi.right - destRoi.left; + HGUInt destRoiHeight = destRoi.bottom - destRoi.top; + + if (roiWidth == destRoiWidth && roiHeight == destRoiHeight) + { + return HGBase_CopyImage(image, destImage); + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp1 = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp1); + if (HGBASE_ERR_OK == ret) + { + HGImage imageTmp2 = NULL; + ret = HGBase_CreateImage(destRoiWidth, destRoiHeight, HGBASE_IMGTYPE_GRAY, imgInfo.origin, &imageTmp2); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ResizeImage(imageTmp1, imageTmp2, interp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp2, destImage); + } + + HGBase_DestroyImage(imageTmp2); + } + + HGBase_DestroyImage(imageTmp1); + } + + return ret; + } + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * channels; + + uint8_t* pDest = destData + destRoi.top * destImgInfo.widthStep + destRoi.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == destImgInfo.origin) + pDest = destData + (destImgInfo.height - destRoi.bottom) * destImgInfo.widthStep + destRoi.left * channels; + + IplImage* pImg = cvCreateImageHeader(cvSize(roiWidth, roiHeight), IPL_DEPTH_8U, channels); + IplImage* pImgDest = cvCreateImageHeader(cvSize(destRoiWidth, destRoiHeight), IPL_DEPTH_8U, channels); + cvSetData(pImg, p, imgInfo.widthStep); + cvSetData(pImgDest, pDest, destImgInfo.widthStep); + int interpolation = (HGIMGPROC_INTERPOTYPE_NN == interp) ? CV_INTER_NN : CV_INTER_LINEAR; + cvResize(pImg, pImgDest, interpolation); + cvReleaseImageHeader(&pImgDest); + cvReleaseImageHeader(&pImg); + + if (imgInfo.origin != destImgInfo.origin) + { + HGBase_ImageFlip(destImage, destImage); + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_ImageAdjustColors(HGImage image, HGImage destImage, + HGInt brightness, HGInt contrast, HGFloat gamma) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + HGUInt type = imgInfo.type; + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_RGB == type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == type || HGBASE_IMGTYPE_RGBA == type) + channels = 4; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageAdjustColors(imageTmp, imageTmp, brightness, contrast, gamma); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * channels; + + cv::Mat img(roiHeight, roiWidth, CV_8UC(channels), p, imgInfo.widthStep); + CImageApplyAdjustColors imgApply(brightness, contrast, gamma); + imgApply.apply(img, 0); + assert(img.data == p); + } + else + { + HGImageInfo destImgInfo; + HGBase_GetImageInfo(destImage, &destImgInfo); + HGUInt destType = destImgInfo.type; + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGByte* destData = NULL; + HGBase_GetImageData(destImage, &destData); + + HGImageRoi destRoi; + HGBase_GetImageROI(destImage, &destRoi); + HGUInt destRoiWidth = destRoi.right - destRoi.left; + HGUInt destRoiHeight = destRoi.bottom - destRoi.top; + + if (roiWidth != destRoiWidth || roiHeight != destRoiHeight) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageAdjustColors(imageTmp, imageTmp, brightness, contrast, gamma); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGBase_CopyImage(image, destImage); + + uint8_t* pDest = destData + destRoi.top * destImgInfo.widthStep + destRoi.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == destImgInfo.origin) + pDest = destData + (destImgInfo.height - destRoi.bottom) * destImgInfo.widthStep + destRoi.left * channels; + + cv::Mat destImg(destRoiHeight, destRoiWidth, CV_8UC(channels), pDest, destImgInfo.widthStep); + CImageApplyAdjustColors imgApply(brightness, contrast, gamma); + imgApply.apply(destImg, 0); + assert(destImg.data == pDest); + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_ImageAutoCrop(HGImage image, HGBool autoCrop, HGBool deskew, HGBool fillBlank, const HGImgAutoCropParam* param, + HGUInt destWidth, HGUInt destHeight, HGUInt destType, HGUInt destOrigin, HGImage* destImage) +{ + if (NULL == image || NULL == destImage) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_BINARY == imgInfo.type || HGBASE_IMGTYPE_RGB == imgInfo.type + || HGBASE_IMGTYPE_RGBA == imgInfo.type || HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + if (0 == destType) + destType = imgInfo.type; + if (0 == destOrigin) + destOrigin = imgInfo.origin; + + ret = HGImgProc_ImageAutoCrop(imageTmp, autoCrop, deskew, fillBlank, param, + destWidth, destHeight, destType, destOrigin, destImage); + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + bool convex = true; + bool fillColor = false; + double threshold = 40.0; + int noise = 8; + int indent = 5; + bool normalCrop = false; + bool dispersion = true; + + if (NULL != param) + { + convex = (bool)param->convex; + fillColor = (bool)param->fillColor; + threshold = param->threshold; + noise = param->noise; + indent = param->indent; + normalCrop = (bool)param->normalCrop; + dispersion = (bool)param->dispersion; + } + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == imgInfo.type) + channels = 3; + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * channels; + + cv::Mat img(roiHeight, roiWidth, CV_8UC(channels), p, imgInfo.widthStep); + + cv::Mat destImg; + autoCrop_desaskew_fillBlank(img, destImg, autoCrop, deskew, fillBlank, destWidth, destHeight, + convex, fillColor, threshold, noise, indent, normalCrop, dispersion); + if (destImg.empty()) + { + return HGIMGPROC_ERR_FAIL; + } + + HGImageInfo newImgInfo; + newImgInfo.width = (HGUInt)destImg.cols; + newImgInfo.height = (HGUInt)destImg.rows; + newImgInfo.type = imgInfo.type; + newImgInfo.widthStep = (HGUInt)destImg.step; + newImgInfo.origin = imgInfo.origin; + + if (0 == destType) + destType = imgInfo.type; + if (0 == destOrigin) + destOrigin = imgInfo.origin; + + return HGBase_CreateImageFromData(destImg.data, &newImgInfo, NULL, destType, destOrigin, destImage); +} + +HGResult HGAPI HGImgProc_ImageBlankCheck(HGImage image, const HGImgBlankCheckParam* param, HGBool* blank) +{ + if (NULL == image || NULL == blank) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_BINARY == imgInfo.type || HGBASE_IMGTYPE_RGB == imgInfo.type + || HGBASE_IMGTYPE_RGBA == imgInfo.type || HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageBlankCheck(imageTmp, param, blank); + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGDouble threshold = 40.0; + HGInt edge = 150; + HGInt blockSize = 10; + HGDouble devTh = 50.0; + HGDouble meanTh = 200.0; + + if (NULL != param) + { + threshold = param->threshold; + edge = param->edge; + blockSize = param->blockSize; + devTh = param->devTh; + meanTh = param->meanTh; + } + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == imgInfo.type) + channels = 3; + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * channels; + + cv::Mat img(roiHeight, roiWidth, CV_8UC(channels), p, imgInfo.widthStep); + + bool ret = CImageApplyDiscardBlank::apply(img, threshold, edge, blockSize, devTh, meanTh); + *blank = ret ? HGTRUE : HGFALSE; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_ImageDrawLine(HGImage image, HGInt x1, HGInt y1, HGInt x2, HGInt y2, + HGColor color, HGUInt width, HGUInt type) +{ + if (NULL == image || 0 == width || type < HGIMGPROC_LINETYPE_SOLID || type > HGIMGPROC_LINETYPE_DASH) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_BINARY == imgInfo.type || HGBASE_IMGTYPE_GRAY == imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageDrawLine(imageTmp, x1, y1, x2, y2, color, width, type); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + uint32_t channels = 3; + if (HGBASE_IMGTYPE_BGRA == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type) + channels = 4; + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * channels; + + IplImage* pImg = cvCreateImageHeader(cvSize(roiWidth, roiHeight), IPL_DEPTH_8U, channels); + cvSetData(pImg, p, imgInfo.widthStep); + + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + { + y1 = roiHeight - y1 - 1; + y2 = roiHeight - y2 - 1; + } + + HGUInt r = HG_GETCOLOR_R(color); + HGUInt g = HG_GETCOLOR_G(color); + HGUInt b = HG_GETCOLOR_B(color); + if (HGBASE_IMGTYPE_RGB == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type) + { + r = HG_GETCOLOR_B(color); + g = HG_GETCOLOR_G(color); + b = HG_GETCOLOR_R(color); + } + + cvLine(pImg, cvPoint(x1, y1), cvPoint(x2, y2), cvScalar(b, g, r), width); + cvReleaseImageHeader(&pImg); + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_AddImageWatermark(HGImage image, const HGChar* text, HGColor color, HGUInt posType, + HGInt locationX, HGInt locationY, const HGImgWatermarkFontParam *fontParam) +{ + if (NULL == image || NULL == text || '\0' == *text || posType < HGIMGPROC_WMPOSTYPE_LEFT + || posType > HGIMGPROC_WMPOSTYPE_LOCATION) + { + return HGBASE_ERR_INVALIDARG; + } + + std::string fontName = "宋体"; + HGUInt fontSize = 20; + HGBool bold = HGFALSE; + HGBool underline = HGFALSE; + HGBool italic = HGFALSE; + HGBool strikeout = HGFALSE; + + if (NULL != fontParam) + { + if (0 == fontParam->fontSize) + { + return HGBASE_ERR_INVALIDARG; + } + + fontName = fontParam->foneName; + fontSize = fontParam->fontSize; + bold = fontParam->bold; + underline = fontParam->underline; + italic = fontParam->italic; + strikeout = fontParam->strikeout; + } + + HGChar moduleName[256]; + HGBase_GetModuleName((void *)HGImgProc_AddImageWatermark, moduleName, 256); + HGChar modulePath[256]; + HGBase_GetFilePath(moduleName, modulePath, 256); + HGChar fontPath[256]; + sprintf(fontPath, "%s%s.ttf", modulePath, fontName.c_str()); + + CvxText cvxText; + HGResult ret = cvxText.Create(fontPath); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + ret = cvxText.DrawString(image, text, color, posType, locationX, locationY, fontSize, bold, underline, italic, strikeout); + return ret; +} + +#if 0 +HGResult HGAPI HGImgProc_ImageBinarization(HGImage image, HGImage destImage, HGUInt thresholdType, + HGInt threshold, HGInt blockSize, HGInt constant) +{ + if (NULL == image || thresholdType < HGIMGPROC_THRESHTYPE_BINARY || thresholdType > HGIMGPROC_THRESHTYPE_ERROR_DIFFUSION) + { + return HGBASE_ERR_INVALIDARG; + } + + CImageApplyBWBinaray::ThresholdType thresholdType2 = CImageApplyBWBinaray::ThresholdType::THRESH_BINARY; + if (HGIMGPROC_THRESHTYPE_OTSU == thresholdType) + thresholdType2 = CImageApplyBWBinaray::ThresholdType::THRESH_OTSU; + else if (HGIMGPROC_THRESHTYPE_ADAPTIVE_GAUSSIAN == thresholdType) + thresholdType2 = CImageApplyBWBinaray::ThresholdType::ADAPTIVE_GAUSSIAN; + else if (HGIMGPROC_THRESHTYPE_ADAPTIVE_MEAN == thresholdType) + thresholdType2 = CImageApplyBWBinaray::ThresholdType::ADAPTIVE_MEAN; + else if (HGIMGPROC_THRESHTYPE_ERROR_DIFFUSION == thresholdType) + thresholdType2 = CImageApplyBWBinaray::ThresholdType::ERROR_DIFFUSION; + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + return HGBASE_ERR_OK; + } + else if (HGBASE_IMGTYPE_GRAY != imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageBinarization(imageTmp, imageTmp, thresholdType, threshold, blockSize, constant); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left; + + cv::Mat img(roiHeight, roiWidth, CV_8UC(1), p, imgInfo.widthStep); + CImageApplyBWBinaray imgApply(thresholdType2, threshold, blockSize, constant); + imgApply.apply(img, 0); + if (img.data != p) + { + for (HGUInt i = 0; i < roiHeight; ++i) + { + memcpy(p + i * imgInfo.widthStep, img.data + i * img.step, roiWidth); + } + } + } + else + { + HGImageInfo destImgInfo; + HGBase_GetImageInfo(destImage, &destImgInfo); + if (imgInfo.type != destImgInfo.type) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGByte* destData = NULL; + HGBase_GetImageData(destImage, &destData); + + HGImageRoi destRoi; + HGBase_GetImageROI(destImage, &destRoi); + HGUInt destRoiWidth = destRoi.right - destRoi.left; + HGUInt destRoiHeight = destRoi.bottom - destRoi.top; + + if (roiWidth != destRoiWidth || roiHeight != destRoiHeight) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + return HGBase_CopyImage(image, destImage); + } + else if (HGBASE_IMGTYPE_GRAY != imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageBinarization(imageTmp, imageTmp, thresholdType, threshold, blockSize, constant); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGBase_CopyImage(image, destImage); + + uint8_t* pDest = destData + destRoi.top * destImgInfo.widthStep + destRoi.left; + if (HGBASE_IMGORIGIN_BOTTOM == destImgInfo.origin) + pDest = destData + (destImgInfo.height - destRoi.bottom) * destImgInfo.widthStep + destRoi.left; + + cv::Mat destImg(destRoiHeight, destRoiWidth, CV_8UC(1), pDest, destImgInfo.widthStep); + CImageApplyBWBinaray imgApply(thresholdType2, threshold, blockSize, constant); + imgApply.apply(destImg, 0); + if (destImg.data != pDest) + { + for (HGUInt i = 0; i < destRoiHeight; ++i) + { + memcpy(pDest + i * destImgInfo.widthStep, destImg.data + i * destImg.step, destRoiWidth); + } + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_ImageExtractChannel(HGImage image, HGImage destImage, HGUInt channelType) +{ + if (NULL == image || channelType < HGIMGPROC_CHANNELTYPE_RED || channelType > HGIMGPROC_CHANNELTYPE_EXCEPT_BLUE) + { + return HGBASE_ERR_INVALIDARG; + } + + CImageApplyChannel::Channel channelType2 = CImageApplyChannel::Red; + if (HGIMGPROC_CHANNELTYPE_GREEN == channelType) + channelType2 = CImageApplyChannel::Green; + else if (HGIMGPROC_CHANNELTYPE_BLUE == channelType) + channelType2 = CImageApplyChannel::Blue; + else if (HGIMGPROC_CHANNELTYPE_ALL == channelType) + channelType2 = CImageApplyChannel::All; + else if (HGIMGPROC_CHANNELTYPE_INVALID == channelType) + channelType2 = CImageApplyChannel::Invalid; + else if (HGIMGPROC_CHANNELTYPE_EXCEPT_RED == channelType) + channelType2 = CImageApplyChannel::Except_Red; + else if (HGIMGPROC_CHANNELTYPE_EXCEPT_GREEN == channelType) + channelType2 = CImageApplyChannel::Except_Green; + else if (HGIMGPROC_CHANNELTYPE_EXCEPT_BLUE == channelType) + channelType2 = CImageApplyChannel::Except_Blue; + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + if (NULL == destImage) + { + destImage = image; + } + else + { + HGImageRoi destRoi; + HGBase_GetImageROI(destImage, &destRoi); + HGUInt destRoiWidth = destRoi.right - destRoi.left; + HGUInt destRoiHeight = destRoi.bottom - destRoi.top; + + if (roiWidth != destRoiWidth || roiHeight != destRoiHeight) + { + return HGBASE_ERR_INVALIDDATA; + } + } + + if (HGBASE_IMGTYPE_BGR != imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageExtractChannel(imageTmp, destImage, channelType); + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * 3; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * 3; + + cv::Mat img(roiHeight, roiWidth, CV_8UC(3), p, imgInfo.widthStep); + CImageApplyChannel imgApply(channelType2); + imgApply.apply(img, 0); + assert(img.data != p); + + HGImageInfo newImgInfo; + newImgInfo.width = (HGUInt)img.cols; + newImgInfo.height = (HGUInt)img.rows; + newImgInfo.type = HGBASE_IMGTYPE_GRAY; + newImgInfo.widthStep = (HGUInt)img.step; + newImgInfo.origin = imgInfo.origin; + + HGImage newImg = NULL; + HGResult ret = HGBase_CreateImageWithData(img.data, &newImgInfo, &newImg); + if (NULL != newImg) + { + ret = HGBase_CopyImage(newImg, destImage); + HGBase_DestroyImage(newImg); + } + + return ret; +} + +HGResult HGAPI HGImgProc_ImageColorRecognition(HGImage image, HGUInt* colorType) +{ + if (NULL == image || NULL == colorType) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + *colorType = HGIMGPROC_COLORTYPE_BINARY; + return HGBASE_ERR_OK; + } + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == imgInfo.type || HGBASE_IMGTYPE_RGB == imgInfo.type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type) + channels = 4; + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * channels; + + if (HGBASE_IMGTYPE_GRAY == imgInfo.type) + { + *colorType = HGIMGPROC_COLORTYPE_BINARY; + + for (HGUInt h = 0; h < roiHeight; ++h) + { + for (HGUInt w = 0; w < roiWidth; ++w) + { + uint8_t *pData = p + imgInfo.widthStep * h + w * channels; + if (0 != *pData && 255 != *pData) + { + *colorType = HGIMGPROC_COLORTYPE_GRAY; + break; + } + } + } + } + else + { + if (HGBASE_IMGTYPE_BGR != imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageColorRecognition(imageTmp, colorType); + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + cv::Mat img(roiHeight, roiWidth, CV_8UC(channels), p, imgInfo.widthStep); + CImageApplyColorRecognition imgApply(CImageApplyColorRecognition::AllColor); + imgApply.apply(img, 0); + + *colorType = HGIMGPROC_COLORTYPE_COLOR; + CImageApplyColorRecognition::ColorType colorType2 = imgApply.getResult(); + if (CImageApplyColorRecognition::Gray == colorType2) + *colorType = HGIMGPROC_COLORTYPE_GRAY; + else if (CImageApplyColorRecognition::Mono == colorType2) + *colorType = HGIMGPROC_COLORTYPE_BINARY; + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_ImageDispersion(HGImage image, HGImage destImage) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + HGUInt type = imgInfo.type; + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BGR != type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageDispersion(imageTmp, imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * 3; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * 3; + + cv::Mat img(roiHeight, roiWidth, CV_8UC(3), p, imgInfo.widthStep); + CImageApplyDispersion imgApply; + imgApply.apply(img, 0); + assert(img.data == p); + } + else + { + HGImageInfo destImgInfo; + HGBase_GetImageInfo(destImage, &destImgInfo); + HGUInt destType = destImgInfo.type; + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGByte* destData = NULL; + HGBase_GetImageData(destImage, &destData); + + HGImageRoi destRoi; + HGBase_GetImageROI(destImage, &destRoi); + HGUInt destRoiWidth = destRoi.right - destRoi.left; + HGUInt destRoiHeight = destRoi.bottom - destRoi.top; + + if (roiWidth != destRoiWidth || roiHeight != destRoiHeight) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BGR != type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageDispersion(imageTmp, imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGBase_CopyImage(image, destImage); + + uint8_t* pDest = destData + destRoi.top * destImgInfo.widthStep + destRoi.left * 3; + if (HGBASE_IMGORIGIN_BOTTOM == destImgInfo.origin) + pDest = destData + (destImgInfo.height - destRoi.bottom) * destImgInfo.widthStep + destRoi.left * 3; + + cv::Mat destImg(destRoiHeight, destRoiWidth, CV_8UC(3), pDest, destImgInfo.widthStep); + CImageApplyDispersion imgApply; + imgApply.apply(destImg, 0); + assert(destImg.data == pDest); + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_ImageFilter(HGImage image, HGImage destImage, HGUInt filterType, HGInt kSize) +{ + if (NULL == image || filterType < HGIMGPROC_FILTERTYPE_SHARPEN || filterType > HGIMGPROC_FILTERTYPE_BRIGHTSHARP) + { + return HGBASE_ERR_INVALIDARG; + } + + CImageApplyFilter::FilterMode filterType2 = CImageApplyFilter::Sharpen; + if (HGIMGPROC_FILTERTYPE_SHARPEN_MORE == filterType) + filterType2 = CImageApplyFilter::Sharpen_More; + else if (HGIMGPROC_FILTERTYPE_AVERBLUR == filterType) + filterType2 = CImageApplyFilter::AverBlur; + else if (HGIMGPROC_FILTERTYPE_AVERBLUR_MORE == filterType) + filterType2 = CImageApplyFilter::AverBlur_More; + else if (HGIMGPROC_FILTERTYPE_BILATERALFILTER == filterType) + filterType2 = CImageApplyFilter::BilateralFilter; + else if (HGIMGPROC_FILTERTYPE_GAUSSIANBLUR == filterType) + filterType2 = CImageApplyFilter::GaussianBlur; + else if (HGIMGPROC_FILTERTYPE_BRIGHTSHARP == filterType) + filterType2 = CImageApplyFilter::BrightSharp; + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == imgInfo.type || HGBASE_IMGTYPE_RGB == imgInfo.type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type) + channels = 4; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BINARY == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type + || HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageFilter(imageTmp, imageTmp, filterType, kSize); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * channels; + + cv::Mat img(roiHeight, roiWidth, CV_8UC(channels), p, imgInfo.widthStep); + CImageApplyFilter imgApply(filterType2, kSize); + imgApply.apply(img, 0); + if (img.data != p) + { + for (HGUInt i = 0; i < roiHeight; ++i) + { + memcpy(p + i * imgInfo.widthStep, img.data + i * img.step, roiWidth * channels); + } + } + } + else + { + HGImageInfo destImgInfo; + HGBase_GetImageInfo(destImage, &destImgInfo); + if (imgInfo.type != destImgInfo.type) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGByte* destData = NULL; + HGBase_GetImageData(destImage, &destData); + + HGImageRoi destRoi; + HGBase_GetImageROI(destImage, &destRoi); + HGUInt destRoiWidth = destRoi.right - destRoi.left; + HGUInt destRoiHeight = destRoi.bottom - destRoi.top; + + if (roiWidth != destRoiWidth || roiHeight != destRoiHeight) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type + || HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageFilter(imageTmp, imageTmp, filterType, kSize); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGBase_CopyImage(image, destImage); + + uint8_t* pDest = destData + destRoi.top * destImgInfo.widthStep + destRoi.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == destImgInfo.origin) + pDest = destData + (destImgInfo.height - destRoi.bottom) * destImgInfo.widthStep + destRoi.left * channels; + + cv::Mat destImg(destRoiHeight, destRoiWidth, CV_8UC(channels), pDest, destImgInfo.widthStep); + CImageApplyFilter imgApply(filterType2, kSize); + imgApply.apply(destImg, 0); + if (destImg.data != pDest) + { + for (HGUInt i = 0; i < destRoiHeight; ++i) + { + memcpy(pDest + i * destImgInfo.widthStep, destImg.data + i * destImg.step, destRoiWidth * channels); + } + } + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_ImageOutHole(HGImage image1, HGImage image2, HGFloat borderSize, HGFloat edgeScale, HGDouble threshold) +{ + if (NULL == image1 || NULL == image2 || image1 == image2) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo1; + HGBase_GetImageInfo(image1, &imgInfo1); + HGImageInfo imgInfo2; + HGBase_GetImageInfo(image2, &imgInfo2); + if (imgInfo1.type != imgInfo2.type || imgInfo1.origin != imgInfo2.origin) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGByte* data1 = NULL; + HGBase_GetImageData(image1, &data1); + HGByte* data2 = NULL; + HGBase_GetImageData(image2, &data2); + + HGImageRoi roi1; + HGBase_GetImageROI(image1, &roi1); + HGUInt roiWidth1 = roi1.right - roi1.left; + HGUInt roiHeight1 = roi1.bottom - roi1.top; + HGImageRoi roi2; + HGBase_GetImageROI(image2, &roi2); + HGUInt roiWidth2 = roi2.right - roi2.left; + HGUInt roiHeight2 = roi2.bottom - roi2.top; + if (roiWidth1 != roiWidth2 || roiHeight1 != roiHeight2) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == imgInfo1.type || HGBASE_IMGTYPE_RGBA == imgInfo1.type + || HGBASE_IMGTYPE_BGRA == imgInfo1.type || HGBASE_IMGTYPE_RGB == imgInfo1.type) + { + HGImage imageTmp1 = NULL; + HGResult ret = HGBase_CloneImage(image1, HGBASE_IMGTYPE_BGR, 0, &imageTmp1); + if (HGBASE_ERR_OK == ret) + { + HGImage imageTmp2 = NULL; + ret = HGBase_CloneImage(image2, HGBASE_IMGTYPE_BGR, 0, &imageTmp2); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageOutHole(imageTmp1, imageTmp2, borderSize, edgeScale, threshold); + if (HGBASE_ERR_OK == ret) + { + HGBase_CopyImage(imageTmp1, image1); + HGBase_CopyImage(imageTmp2, image2); + } + + HGBase_DestroyImage(imageTmp2); + } + + HGBase_DestroyImage(imageTmp1); + } + + return ret; + } + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == imgInfo1.type || HGBASE_IMGTYPE_RGB == imgInfo1.type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == imgInfo1.type || HGBASE_IMGTYPE_RGBA == imgInfo1.type) + channels = 4; + + uint8_t* p1 = data1 + roi1.top * imgInfo1.widthStep + roi1.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo1.origin) + p1 = data1 + (imgInfo1.height - roi1.bottom) * imgInfo1.widthStep + roi1.left * channels; + cv::Mat img1(roiHeight1, roiWidth1, CV_8UC(channels), p1, imgInfo1.widthStep); + + uint8_t* p2 = data2 + roi2.top * imgInfo2.widthStep + roi2.left * channels; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo2.origin) + p2 = data2 + (imgInfo2.height - roi2.bottom) * imgInfo2.widthStep + roi2.left * channels; + cv::Mat img2(roiHeight2, roiWidth2, CV_8UC(channels), p2, imgInfo2.widthStep); + + std::vector mats; + mats.push_back(img1); + mats.push_back(img2); + CImageApplyOutHole imgApply(borderSize, edgeScale, threshold); + imgApply.apply(mats, true); + assert(mats[0].data == p1); + assert(mats[1].data == p2); + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_ImageHSVCorrect(HGImage image, HGImage destImage, HGUInt correctOption, HGBool cvtGray, HGColor color) +{ + if (NULL == image || correctOption < HGIMGPROC_CORRECTOPTION_DEFAULT || correctOption > HGIMGPROC_CORRECTOPTION_RED_REMOVAL) + { + return HGBASE_ERR_INVALIDARG; + } + + CImageApplyHSVCorrect::CorrectOption correctOption2 = CImageApplyHSVCorrect::Deafault; + if (HGIMGPROC_CORRECTOPTION_LOWSATURATION_REMOVAL == correctOption) + correctOption2 = CImageApplyHSVCorrect::LowSaturation_Removal; + else if (HGIMGPROC_CORRECTOPTION_RED_REMOVAL == correctOption) + correctOption2 = CImageApplyHSVCorrect::Red_Removal; + bool cvtGray2 = cvtGray ? true : false; + HGUInt r = HG_GETCOLOR_R(color); + HGUInt g = HG_GETCOLOR_G(color); + HGUInt b = HG_GETCOLOR_B(color); + uint color2 = (uint)(((HGUInt)r << 16) | ((HGUInt)g << 8) | (HGUInt)b); + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + HGUInt type = imgInfo.type; + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BGR != type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageHSVCorrect(imageTmp, imageTmp, correctOption, cvtGray, color); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * 3; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * 3; + + cv::Mat img(roiHeight, roiWidth, CV_8UC(3), p, imgInfo.widthStep); + CImageApplyHSVCorrect imgApply(correctOption2, cvtGray2, color2); + imgApply.apply(img, 0); + assert(img.data == p); + } + else + { + HGImageInfo destImgInfo; + HGBase_GetImageInfo(destImage, &destImgInfo); + HGUInt destType = destImgInfo.type; + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGByte* destData = NULL; + HGBase_GetImageData(destImage, &destData); + + HGImageRoi destRoi; + HGBase_GetImageROI(destImage, &destRoi); + HGUInt destRoiWidth = destRoi.right - destRoi.left; + HGUInt destRoiHeight = destRoi.bottom - destRoi.top; + + if (roiWidth != destRoiWidth || roiHeight != destRoiHeight) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BGR != type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageHSVCorrect(imageTmp, imageTmp, correctOption, cvtGray, color); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGBase_CopyImage(image, destImage); + + uint8_t* pDest = destData + destRoi.top * destImgInfo.widthStep + destRoi.left * 3; + if (HGBASE_IMGORIGIN_BOTTOM == destImgInfo.origin) + pDest = destData + (destImgInfo.height - destRoi.bottom) * destImgInfo.widthStep + destRoi.left * 3; + + cv::Mat destImg(destRoiHeight, destRoiWidth, CV_8UC(3), pDest, destImgInfo.widthStep); + CImageApplyHSVCorrect imgApply(correctOption2, cvtGray2, color2); + imgApply.apply(destImg, 0); + assert(destImg.data == pDest); + } + + return HGBASE_ERR_OK; +} +#endif + +HGResult HGAPI HGImgProc_ImageFadeBkColor(HGImage image, HGImage destImage, const HGImgFaceBkColorParam* param) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + int threshold = 100; + int offset = 0; + int range = 40; + if (NULL != param) + { + threshold = param->threshold; + offset = param->offset; + range = param->range; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + HGUInt type = imgInfo.type; + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BGR != type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageFadeBkColor(imageTmp, imageTmp, param); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + uint8_t* p = data + roi.top * imgInfo.widthStep + roi.left * 3; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + p = data + (imgInfo.height - roi.bottom) * imgInfo.widthStep + roi.left * 3; + + cv::Mat img(roiHeight, roiWidth, CV_8UC(3), p, imgInfo.widthStep); + CImageApplyFadeBackGroudColor imgApply(threshold, offset, range); + imgApply.apply(img, 0); + assert(img.data == p); + } + else + { + HGImageInfo destImgInfo; + HGBase_GetImageInfo(destImage, &destImgInfo); + HGUInt destType = destImgInfo.type; + if (type != destType) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGByte* destData = NULL; + HGBase_GetImageData(destImage, &destData); + + HGImageRoi destRoi; + HGBase_GetImageROI(destImage, &destRoi); + HGUInt destRoiWidth = destRoi.right - destRoi.left; + HGUInt destRoiHeight = destRoi.bottom - destRoi.top; + + if (roiWidth != destRoiWidth || roiHeight != destRoiHeight) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BGR != type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_BGR, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageFadeBkColor(imageTmp, imageTmp, param); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGBase_CopyImage(image, destImage); + + uint8_t* pDest = destData + destRoi.top * destImgInfo.widthStep + destRoi.left * 3; + if (HGBASE_IMGORIGIN_BOTTOM == destImgInfo.origin) + pDest = destData + (destImgInfo.height - destRoi.bottom) * destImgInfo.widthStep + destRoi.left * 3; + + cv::Mat destImg(destRoiHeight, destRoiWidth, CV_8UC(3), pDest, destImgInfo.widthStep); + CImageApplyFadeBackGroudColor imgApply(threshold, offset, range); + imgApply.apply(destImg, 0); + assert(destImg.data == pDest); + } + + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_ImageDecontamination(HGImage image, HGImage destImage, HGUInt decoType, HGUInt x, HGUInt y, + HGUInt width, HGUInt height, HGColor color) +{ + if (NULL == image || decoType < HGIMGPROC_DECOTYPE_INSIDE || decoType > HGIMGPROC_DECOTYPE_OUTSIDE + || 0 == width || 0 == height) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + + HGByte* data = NULL; + HGBase_GetImageData(image, &data); + + HGImageRoi roi; + HGBase_GetImageROI(image, &roi); + HGUInt roiWidth = roi.right - roi.left; + HGUInt roiHeight = roi.bottom - roi.top; + + if (x + width > roiWidth || y + height > roiHeight) + { + return HGBASE_ERR_INVALIDARG; + } + + uint32_t channels = 1; + if (HGBASE_IMGTYPE_BGR == imgInfo.type || HGBASE_IMGTYPE_RGB == imgInfo.type) + channels = 3; + else if (HGBASE_IMGTYPE_BGRA == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type) + channels = 4; + uint32_t dataSize = roiWidth * channels; + + HGUInt r = HG_GETCOLOR_R(color); + HGUInt g = HG_GETCOLOR_G(color); + HGUInt b = HG_GETCOLOR_B(color); + HGUInt v = (r * 76 + g * 150 + b * 30) >> 8; + + if (NULL == destImage || image == destImage) + { + if (HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageDecontamination(imageTmp, imageTmp, decoType, x, y, width, height, color); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, image); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* p = data + (HGUSize)roi.top * (HGUSize)imgInfo.widthStep + roi.left * channels; + HGInt step = (HGInt)imgInfo.widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + { + p = data + (HGUSize)(imgInfo.height - roi.top - 1) * (HGUSize)imgInfo.widthStep + roi.left * channels; + step = -(HGInt)imgInfo.widthStep; + } + + if (HGBASE_IMGTYPE_RGB == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type + || HGBASE_IMGTYPE_BGR == imgInfo.type || HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + if (HGBASE_IMGTYPE_BGR == imgInfo.type || HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + r = HG_GETCOLOR_B(color); + g = HG_GETCOLOR_G(color); + b = HG_GETCOLOR_R(color); + } + + if (HGIMGPROC_DECOTYPE_INSIDE == decoType) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = p + (HGSize)i * (HGSize)step; + for (int32_t j = 0; j < (int32_t)roiWidth; ++j) + { + HGByte* pEx2 = pEx + j * channels; + if ((j >= (int32_t)x && j < (int32_t)(x + width)) && (i >= (int32_t)y && i < (int32_t)(y + height))) + { + pEx2[0] = r; + pEx2[1] = g; + pEx2[2] = b; + } + } + } + } + else + { + assert(HGIMGPROC_DECOTYPE_OUTSIDE == decoType); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = p + (HGSize)i * (HGSize)step; + for (int32_t j = 0; j < (int32_t)roiWidth; ++j) + { + HGByte* pEx2 = pEx + j * channels; + if ((j >= (int32_t)x && j < (int32_t)(x + width)) && (i >= (int32_t)y && i < (int32_t)(y + height))) + { + + } + else + { + pEx2[0] = r; + pEx2[1] = g; + pEx2[2] = b; + } + } + } + } + } + else + { + assert(HGBASE_IMGTYPE_GRAY == imgInfo.type); + + if (HGIMGPROC_DECOTYPE_INSIDE == decoType) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = p + (HGSize)i * (HGSize)step; + for (int32_t j = 0; j < (int32_t)roiWidth; ++j) + { + HGByte* pEx2 = pEx + j * channels; + if ((j >= (int32_t)x && j < (int32_t)(x + width)) && (i >= (int32_t)y && i < (int32_t)(y + height))) + *pEx2 = v; + } + } + } + else + { + assert(HGIMGPROC_DECOTYPE_OUTSIDE == decoType); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pEx = p + (HGSize)i * (HGSize)step; + for (int32_t j = 0; j < (int32_t)roiWidth; ++j) + { + HGByte* pEx2 = pEx + j * channels; + if ((j >= (int32_t)x && j < (int32_t)(x + width)) && (i >= (int32_t)y && i < (int32_t)(y + height))) + { + + } + else + *pEx2 = v; + } + } + } + } + } + else + { + HGImageInfo destImgInfo; + HGBase_GetImageInfo(destImage, &destImgInfo); + if (imgInfo.type != destImgInfo.type) + { + return HGBASE_ERR_INVALIDDATA; + } + + HGByte* destData = NULL; + HGBase_GetImageData(destImage, &destData); + + HGImageRoi destRoi; + HGBase_GetImageROI(destImage, &destRoi); + HGUInt destRoiWidth = destRoi.right - destRoi.left; + HGUInt destRoiHeight = destRoi.bottom - destRoi.top; + + if (roiWidth != destRoiWidth || roiHeight != destRoiHeight) + { + return HGBASE_ERR_INVALIDDATA; + } + + if (HGBASE_IMGTYPE_BINARY == imgInfo.type) + { + HGImage imageTmp = NULL; + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); + if (HGBASE_ERR_OK == ret) + { + ret = HGImgProc_ImageDecontamination(imageTmp, imageTmp, decoType, x, y, width, height, color); + if (HGBASE_ERR_OK == ret) + { + ret = HGBase_CopyImage(imageTmp, destImage); + } + + HGBase_DestroyImage(imageTmp); + } + + return ret; + } + + HGByte* src = data + (HGUSize)roi.top * (HGUSize)imgInfo.widthStep + roi.left * channels; + HGInt srcStep = (HGInt)imgInfo.widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) + { + src = data + (HGUSize)(imgInfo.height - roi.top - 1) * (HGUSize)imgInfo.widthStep + roi.left * channels; + srcStep = -(HGInt)imgInfo.widthStep; + } + + HGByte* dest = destData + (HGUSize)destRoi.top * (HGUSize)destImgInfo.widthStep + destRoi.left * channels; + HGInt destStep = (HGInt)destImgInfo.widthStep; + if (HGBASE_IMGORIGIN_BOTTOM == destImgInfo.origin) + { + dest = destData + (HGUSize)(destImgInfo.height - destRoi.top - 1) * (HGUSize)destImgInfo.widthStep + destRoi.left * channels; + destStep = -(HGInt)destImgInfo.widthStep; + } + + if (HGBASE_IMGTYPE_RGB == imgInfo.type || HGBASE_IMGTYPE_RGBA == imgInfo.type + || HGBASE_IMGTYPE_BGR == imgInfo.type || HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + if (HGBASE_IMGTYPE_BGR == imgInfo.type || HGBASE_IMGTYPE_BGRA == imgInfo.type) + { + r = HG_GETCOLOR_B(color); + g = HG_GETCOLOR_G(color); + b = HG_GETCOLOR_R(color); + } + + if (HGIMGPROC_DECOTYPE_INSIDE == decoType) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + for (int32_t j = 0; j < (int32_t)roiWidth; ++j) + { + HGByte* pSrcEx2 = pSrcEx + j * channels; + HGByte* pDestEx2 = pDestEx + j * channels; + if ((j >= (int32_t)x && j < (int32_t)(x + width)) && (i >= (int32_t)y && i < (int32_t)(y + height))) + { + pDestEx2[0] = r; + pDestEx2[1] = g; + pDestEx2[2] = b; + } + else + { + pDestEx2[0] = pSrcEx2[0]; + pDestEx2[1] = pSrcEx2[1]; + pDestEx2[2] = pSrcEx2[2]; + } + } + } + } + else + { + assert(HGIMGPROC_DECOTYPE_OUTSIDE == decoType); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + for (int32_t j = 0; j < (int32_t)roiWidth; ++j) + { + HGByte* pSrcEx2 = pSrcEx + j * channels; + HGByte* pDestEx2 = pDestEx + j * channels; + if ((j >= (int32_t)x && j < (int32_t)(x + width)) && (i >= (int32_t)y && i < (int32_t)(y + height))) + { + pDestEx2[0] = pSrcEx2[0]; + pDestEx2[1] = pSrcEx2[1]; + pDestEx2[2] = pSrcEx2[2]; + } + else + { + pDestEx2[0] = r; + pDestEx2[1] = g; + pDestEx2[2] = b; + } + } + } + } + } + else + { + assert(HGBASE_IMGTYPE_GRAY == imgInfo.type); + + if (HGIMGPROC_DECOTYPE_INSIDE == decoType) + { + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + for (int32_t j = 0; j < (int32_t)roiWidth; ++j) + { + HGByte* pSrcEx2 = pSrcEx + j * channels; + HGByte* pDestEx2 = pDestEx + j * channels; + if ((j >= (int32_t)x && j < (int32_t)(x + width)) && (i >= (int32_t)y && i < (int32_t)(y + height))) + *pDestEx2 = v; + else + *pDestEx2 = *pSrcEx2; + } + } + } + else + { + assert(HGIMGPROC_DECOTYPE_OUTSIDE == decoType); + + //#pragma omp parallel for + for (int32_t i = 0; i < (int32_t)roiHeight; ++i) + { + HGByte* pSrcEx = src + (HGSize)i * (HGSize)srcStep; + HGByte* pDestEx = dest + (HGSize)i * (HGSize)destStep; + for (int32_t j = 0; j < (int32_t)roiWidth; ++j) + { + HGByte* pSrcEx2 = pSrcEx + j * channels; + HGByte* pDestEx2 = pDestEx + j * channels; + if ((j >= (int32_t)x && j < (int32_t)(x + width)) && (i >= (int32_t)y && i < (int32_t)(y + height))) + *pDestEx2 = *pSrcEx2; + else + *pDestEx2 = v; + } + } + } + } + } + + return HGBASE_ERR_OK; +} diff --git a/app/modules/imgproc/HGImgProc.h b/app/modules/imgproc/HGImgProc.h new file mode 100644 index 0000000..8844759 --- /dev/null +++ b/app/modules/imgproc/HGImgProc.h @@ -0,0 +1,205 @@ +#ifndef __HGIMGPROC_H__ +#define __HGIMGPROC_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgProcErr.h" +#include "../base/HGImage.h" + +/* 最近邻插值 */ +#define HGIMGPROC_INTERPOTYPE_NN 1L +/* 双线性插值 */ +#define HGIMGPROC_INTERPOTYPE_LINEAR 2L + +/* 线条类型-实线 */ +#define HGIMGPROC_LINETYPE_SOLID 1L +/* 线条类型-虚线 */ +#define HGIMGPROC_LINETYPE_DASH 2L + +/* 水印位置-左侧 */ +#define HGIMGPROC_WMPOSTYPE_LEFT 1L +/* 水印位置-上侧 */ +#define HGIMGPROC_WMPOSTYPE_TOP 2L +/* 水印位置-右侧 */ +#define HGIMGPROC_WMPOSTYPE_RIGHT 3L +/* 水印位置-下侧 */ +#define HGIMGPROC_WMPOSTYPE_BOTTOM 4L +/* 水印位置-左上 */ +#define HGIMGPROC_WMPOSTYPE_LEFTTOP 5L +/* 水印位置-右上 */ +#define HGIMGPROC_WMPOSTYPE_RIGHTTOP 6L +/* 水印位置-左下 */ +#define HGIMGPROC_WMPOSTYPE_LEFTBOTTOM 7L +/* 水印位置-右下 */ +#define HGIMGPROC_WMPOSTYPE_RIGHTBOTTOM 8L +/* 水印位置-中间 */ +#define HGIMGPROC_WMPOSTYPE_CENTER 9L +/* 水印位置-自定义 */ +#define HGIMGPROC_WMPOSTYPE_LOCATION 10L + +/* 内部去污 */ +#define HGIMGPROC_DECOTYPE_INSIDE 1L +/* 外部去污 */ +#define HGIMGPROC_DECOTYPE_OUTSIDE 2L + +#pragma pack(push) +#pragma pack(4) + +/* 自动裁剪参数 */ +typedef struct +{ + HGBool convex; /* 黑底填充时的填充方式, HGTRUE为凸多边形填充,HGFALSE为凹多边形填充,默认HGTRUE */ + HGBool fillColor; /* 黑底填充时采用自适应色彩填充,HGFALSE为白色填充,HGTRUE为自适应文稿底色填充,默认HGFALSE */ + HGDouble threshold; /* 二值化阈值,取值范围(0, 255),默认40 */ + HGInt noise; /* 除噪像素,能够消除noise宽度的背景竖条纹干扰,默认8 */ + HGInt indent; /* 轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进indent像素,默认5 */ + HGBool normalCrop; /* crop deskew fillBlank失效,固定裁切采用最传统的裁切方式,默认HGFALSE */ + HGBool dispersion; /* 是否除色散,默认HGTRUE */ +}HGImgAutoCropParam; + +/* 白底检查参数 */ +typedef struct +{ + HGDouble threshold; /* 默认40 */ + HGInt edge; /* 默认150 */ + HGInt blockSize; /* 默认10 */ + HGDouble devTh; /* 默认50 */ + HGDouble meanTh; /* 默认200 */ +}HGImgBlankCheckParam; + +/* 水印字体参数 */ +typedef struct +{ + HGChar foneName[64]; /* 字体名, windows上为GBK编码, linux上为UTF8编码, 默认宋体 */ + HGUInt fontSize; /* 字号, 默认20 */ + HGBool bold; /* 是否粗体, 默认HGFALSE */ + HGBool underline; /* 是否有下划线, 默认HGFALSE */ + HGBool italic; /* 是否斜体, 默认HGFALSE */ + HGBool strikeout; /* 是否有删除线, 默认HGFALSE */ +}HGImgWatermarkFontParam; + +/* 去底色参数 */ +typedef struct +{ + HGInt threshold; /* 默认100 */ + HGInt offset; /* 默认0 */ + HGInt range; /* 默认40 */ +}HGImgFaceBkColorParam; + +#pragma pack(pop) + +/* 图像缩放 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 3) interpolation: in, 插值方式, 参见HGIMGPROC_INTERPOTYPE_* +* 说明: +* 1) 操作的只是图像的ROI区域 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage不能是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ResizeImage(HGImage image, HGImage destImage, HGUInt interp); + +/* +* 图像色彩调整 +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 3) brightness: in, 亮度增加值, -255至255之间 +* 4) contrast: in, 对比度增加值, -127至127之间 +* 5) gamma: 伽马增加值, 0.1至5.0之间 +* 说明: +* 1) 操作的只是图像的ROI区域, ROI区域的大小必须一致 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageAdjustColors(HGImage image, HGImage destImage, + HGInt brightness, HGInt contrast, HGFloat gamma); + +/* +* 图像自动裁剪 +* 1) image: in, 图像句柄 +* 2) autoCrop: in, 是否自动裁剪, 为HGTRUE则忽略destWidth和destHeight +* 3) deskew: in, 是否纠偏 +* 4) fillBlank: in, 是否进行黑底填充 +* 5) param: in, 参数, 为NULL时使用默认参数 +* 6) destWidth: in, 目标图像宽度 +* 7) destHeight: in, 目标图像高度 +* 8) destType: in, 目标图像类型, 0表示和image一样 +* 9) destOrigin: in, 目标图像数据排列方式, 0表示和image一样 +* 10) destImage: out, 输出的目标图像句柄, 不用的时候需要调用HGBase_DestroyImage销毁 +* 说明: +* 1) 操作的只是image的ROI区域 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageAutoCrop(HGImage image, HGBool autoCrop, HGBool deskew, HGBool fillBlank, const HGImgAutoCropParam* param, + HGUInt destWidth, HGUInt destHeight, HGUInt destType, HGUInt destOrigin, HGImage* destImage); + +/* 判断图像是否是空白 +* 1) image: in, 图像句柄 +* 2) param: in, 参数, 为NULL时使用默认参数 +* 3) blank: out, HGTRUE为空白图像, HGFALSE为非空白图像 +* 说明: +* 1) 操作的只是image的ROI区域 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageBlankCheck(HGImage image, const HGImgBlankCheckParam *param, HGBool *blank); + +/* 图像画线 +* 1) image: in, 图像句柄 +* 2) x1: in, 第一个点x坐标 +* 3) y1: in, 第一个点y坐标 +* 4) x2: in, 第二个点x坐标 +* 5) y2: in, 第二个点y坐标 +* 6) color: in, 颜色 +* 7) width: in, 线宽 +* 8) type: in, 表示线类型, 参见HGIMGPROC_LINETYPE_* +* 说明: +* 1) 操作的只是图像的ROI区域 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageDrawLine(HGImage image, HGInt x1, HGInt y1, HGInt x2, HGInt y2, + HGColor color, HGUInt width, HGUInt type); + +/* 添加图像水印 +* 1) image: in, 图像句柄 +* 2) text: 水印文本, windows上为GBK编码, linux上为UTF8编码 +* 3) color: 颜色 +* 4) posType: 位置, 见HGIMGPROC_WMPOSTYPE_* +* 5) locationX: 当posType为HGIMGPROC_WMPOSTYPE_LOCATION时表示x坐标 +* 6) locationY: 当posType为HGIMGPROC_WMPOSTYPE_LOCATION时表示y坐标 +* 7) fontParam: 字体参数, 为NULL时使用默认参数 +* 说明: +* 1) 操作的只是图像的ROI区域 +*/ +HGEXPORT HGResult HGAPI HGImgProc_AddImageWatermark(HGImage image, const HGChar *text, HGColor color, HGUInt posType, + HGInt locationX, HGInt locationY, const HGImgWatermarkFontParam *fontParam); + +/* 消除文稿纸张底色 +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 3) param: in, 参数, 为NULL时使用默认参数 +* 说明: +* 1) 操作的只是图像的ROI区域, ROI区域的大小必须一致 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageFadeBkColor(HGImage image, HGImage destImage, const HGImgFaceBkColorParam *param); + +/* 图像去污 +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 3) decoType: in, 去污类型, 参见HGIMGPROC_DECOTYPE_* +* 4) x: in, 选择区域的x坐标 +* 5) y: in, 选择区域的y坐标 +* 6) width: in, 选择区域的宽 +* 7) height: in, 选择区域的高 +* 说明: +* 1) 操作的只是图像的ROI区域, ROI区域的大小必须一致 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageDecontamination(HGImage image, HGImage destImage, HGUInt decoType, HGUInt x, HGUInt y, + HGUInt width, HGUInt height, HGColor color); + +#endif /* __HGIMGPROC_H__ */ \ No newline at end of file diff --git a/app/modules/imgproc/HGImgProcErr.h b/app/modules/imgproc/HGImgProcErr.h new file mode 100644 index 0000000..cd6818b --- /dev/null +++ b/app/modules/imgproc/HGImgProcErr.h @@ -0,0 +1,13 @@ +#ifndef __HGIMGPROCERR_H__ +#define __HGIMGPROCERR_H__ + +/* 一般错误 */ +#define HGIMGPROC_ERR_FAIL 0x00003001L + +/* OCR初始化错误 */ +#define HGIMGPROC_ERR_OCRINIT 0x00003002L + +/* OCR错误 */ +#define HGIMGPROC_ERR_OCR 0x00003003L + +#endif /* __HGIMGPROCERR_H__ */ \ No newline at end of file diff --git a/app/modules/imgproc/HGOCR.cpp b/app/modules/imgproc/HGOCR.cpp new file mode 100644 index 0000000..5422b22 --- /dev/null +++ b/app/modules/imgproc/HGOCR.cpp @@ -0,0 +1,188 @@ +#include "HGOCR.h" +#include "HGOCRBase.hpp" +#include "HGOCRHanvon.hpp" +#include "HGOCRTesseract.hpp" +#include "HGOCRRetImpl.hpp" + +HGResult HGAPI HGImgProc_CreateOCRMgr(HGUInt algo, HGOCRMgr* ocrMgr) +{ + if (NULL == ocrMgr) + { + return HGBASE_ERR_INVALIDARG; + } + + if (HGIMGPROC_OCRALGO_DEFAULT == algo) + { + HGOCRBase* ocrMgrImpl = new HGOCRHanvon; + HGResult ret = ocrMgrImpl->Init(); + if (HGBASE_ERR_OK != ret) + { + delete ocrMgrImpl; + ocrMgrImpl = new HGOCRTesseract; + ret = ocrMgrImpl->Init(); + if (HGBASE_ERR_OK != ret) + { + delete ocrMgrImpl; + return ret; + } + } + + *ocrMgr = (HGOCRMgr)ocrMgrImpl; + return HGBASE_ERR_OK; + } + else if (HGIMGPROC_OCRALGO_HANVON == algo) + { + HGOCRBase* ocrMgrImpl = new HGOCRHanvon; + HGResult ret = ocrMgrImpl->Init(); + if (HGBASE_ERR_OK != ret) + { + delete ocrMgrImpl; + return ret; + } + + *ocrMgr = (HGOCRMgr)ocrMgrImpl; + return HGBASE_ERR_OK; + } + else if (HGIMGPROC_OCRALGO_TESSERACT == algo) + { + HGOCRBase* ocrMgrImpl = new HGOCRTesseract; + HGResult ret = ocrMgrImpl->Init(); + if (HGBASE_ERR_OK != ret) + { + delete ocrMgrImpl; + return ret; + } + + *ocrMgr = (HGOCRMgr)ocrMgrImpl; + return HGBASE_ERR_OK; + } + + return HGBASE_ERR_INVALIDARG; +} + +HGResult HGAPI HGImgProc_DestroyOCRMgr(HGOCRMgr ocrMgr) +{ + if (NULL == ocrMgr) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOCRBase* ocrMgrImpl = (HGOCRBase*)ocrMgr; + HGResult ret = ocrMgrImpl->Deinit(); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + delete ocrMgrImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_ImageOCR(HGOCRMgr ocrMgr, HGImage image, HGOCRRet* ocrRet) +{ + if (NULL == ocrMgr) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOCRBase* ocrMgrImpl = (HGOCRBase*)ocrMgr; + HGOCRRetImpl* ocrRetImpl = NULL; + HGResult ret = ocrMgrImpl->ImageOCR(image, &ocrRetImpl); + if (HGBASE_ERR_OK != ret) + { + assert(NULL == ocrRetImpl); + return ret; + } + + *ocrRet = (HGOCRRet)ocrRetImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_DestroyOCRRet(HGOCRRet ocrRet) +{ + if (NULL == ocrRet) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOCRRetImpl* ocrRetImpl = (HGOCRRetImpl*)ocrRet; + delete ocrRetImpl; + return HGBASE_ERR_OK; +} + +HGResult HGAPI HGImgProc_GetOCRRetBlockCount(HGOCRRet ocrRet, HGUInt* count) +{ + if (NULL == ocrRet) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOCRRetImpl* ocrRetImpl = (HGOCRRetImpl*)ocrRet; + return ocrRetImpl->GetBlockCount(count); +} + +HGResult HGAPI HGImgProc_GetOCRRetBlockText(HGOCRRet ocrRet, HGUInt index, const HGChar** text) +{ + if (NULL == ocrRet) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOCRRetImpl* ocrRetImpl = (HGOCRRetImpl*)ocrRet; + return ocrRetImpl->GetBlockText(index, text); +} + +HGResult HGAPI HGImgProc_ImageOCRToFile(HGOCRMgr ocrMgr, HGImage image, HGUInt outType, const HGChar* outFileName) +{ + if (NULL == ocrMgr) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOCRBase* ocrMgrImpl = (HGOCRBase*)ocrMgr; + return ocrMgrImpl->ImageOCRToFile(image, outType, outFileName); +} + +HGResult HGAPI HGImgProc_ImageTextDirectOCR(HGOCRMgr ocrMgr, HGImage image, HGUInt* direct) +{ + if (NULL == ocrMgr) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOCRBase* ocrMgrImpl = (HGOCRBase*)ocrMgr; + return ocrMgrImpl->ImageTextDirectOCR(image, direct); +} + +HGResult HGAPI HGImgProc_AddToImageOCRList(HGOCRMgr ocrMgr, HGImage image) +{ + if (NULL == ocrMgr) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOCRBase* ocrMgrImpl = (HGOCRBase*)ocrMgr; + return ocrMgrImpl->AddToImageList(image); +} + +HGResult HGAPI HGImgProc_ClearImageOCRList(HGOCRMgr ocrMgr) +{ + if (NULL == ocrMgr) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOCRBase* ocrMgrImpl = (HGOCRBase*)ocrMgr; + return ocrMgrImpl->ClearImageList(); +} + +HGResult HGAPI HGImgProc_ImageListOCRToFile(HGOCRMgr ocrMgr, HGUInt outType, const HGChar* outFileName, HGImageListOcrFunc func, HGPointer param) +{ + if (NULL == ocrMgr) + { + return HGBASE_ERR_INVALIDARG; + } + + HGOCRBase* ocrMgrImpl = (HGOCRBase*)ocrMgr; + return ocrMgrImpl->ImageListOCRToFile(outType, outFileName, func, param); +} \ No newline at end of file diff --git a/app/modules/imgproc/HGOCR.h b/app/modules/imgproc/HGOCR.h new file mode 100644 index 0000000..0e33414 --- /dev/null +++ b/app/modules/imgproc/HGOCR.h @@ -0,0 +1,85 @@ +#ifndef __HGOCR_H__ +#define __HGOCR_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgProcErr.h" +#include "../base/HGImage.h" + +HG_DECLARE_HANDLE(HGOCRMgr); +HG_DECLARE_HANDLE(HGOCRRet); + +/* algo */ +#define HGIMGPROC_OCRALGO_DEFAULT 0L +#define HGIMGPROC_OCRALGO_HANVON 1L +#define HGIMGPROC_OCRALGO_TESSERACT 2L + +/* RTF */ +#define HGIMGPROC_OCROUTTYPE_RTF 1L +/* XLS */ +#define HGIMGPROC_OCROUTTYPE_XLS 2L +/* TXT */ +#define HGIMGPROC_OCROUTTYPE_TXT 3L +/* PDF */ +#define HGIMGPROC_OCROUTTYPE_PDF 4L +/* OFD */ +#define HGIMGPROC_OCROUTTYPE_OFD 5L + +/* 未旋转 */ +#define HGIMGPROC_OCRTEXTDIRECT_ORI 1L +/* 顺时针旋转了90度 */ +#define HGIMGPROC_OCRTEXTDIRECT_RIGHT 2L +/* 逆时针旋转了90度 */ +#define HGIMGPROC_OCRTEXTDIRECT_LEFT 3L +/* 旋转了180度 */ +#define HGIMGPROC_OCRTEXTDIRECT_180 4L + +/* 多页OCR进度 +*/ +typedef HGInt (HGAPI *HGImageListOcrFunc)(HGUInt total, HGUInt now, HGPointer param); + +/* 初始化OCR模块 +*/ +HGEXPORT HGResult HGAPI HGImgProc_CreateOCRMgr(HGUInt algo, HGOCRMgr *ocrMgr); + +/* 反初始化OCR模块 +*/ +HGEXPORT HGResult HGAPI HGImgProc_DestroyOCRMgr(HGOCRMgr ocrMgr); + +/* 图像OCR +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageOCR(HGOCRMgr ocrMgr, HGImage image, HGOCRRet *ocrRet); + +/* 销毁OCR结果 +*/ +HGEXPORT HGResult HGAPI HGImgProc_DestroyOCRRet(HGOCRRet ocrRet); + +/* 获取OCR结果块数量 +*/ +HGEXPORT HGResult HGAPI HGImgProc_GetOCRRetBlockCount(HGOCRRet ocrRet, HGUInt *count); + +/* 获取OCR结果块文本 +*/ +HGEXPORT HGResult HGAPI HGImgProc_GetOCRRetBlockText(HGOCRRet ocrRet, HGUInt index, const HGChar **text); + +/* 图像OCR到文件 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageOCRToFile(HGOCRMgr ocrMgr, HGImage image, HGUInt outType, const HGChar *outFileName); + +/* 获取图像识别方向 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageTextDirectOCR(HGOCRMgr ocrMgr, HGImage image, HGUInt *direct); + +/* 添加到图像OCR列表 +*/ +HGEXPORT HGResult HGAPI HGImgProc_AddToImageOCRList(HGOCRMgr ocrMgr, HGImage image); + +/* 清理图像OCR列表 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ClearImageOCRList(HGOCRMgr ocrMgr); + +/* 图像列表OCR到文件 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageListOCRToFile(HGOCRMgr ocrMgr, HGUInt outType, const HGChar* outFileName, HGImageListOcrFunc func, HGPointer param); + +#endif /* __HGOCR_H__ */ \ No newline at end of file diff --git a/app/modules/imgproc/HGOCRBase.cpp b/app/modules/imgproc/HGOCRBase.cpp new file mode 100644 index 0000000..c89cfc4 --- /dev/null +++ b/app/modules/imgproc/HGOCRBase.cpp @@ -0,0 +1,71 @@ +#include "HGOCRBase.hpp" +#include "HGOCR.h" +#include "../base/HGInc.h" + +HGUInt HGOCRBase::GetOutTypeByFileName(const HGChar* fileName) +{ + if (NULL == fileName) + { + return 0; + } + + const char* p = strrchr(fileName, '.'); + if (NULL == p) + { + return 0; + } + +#if defined(HG_CMP_MSC) + if (0 == _stricmp(p, ".pdf")) + { + return HGIMGPROC_OCROUTTYPE_PDF; + } + + if (0 == _stricmp(p, ".rtf")) + { + return HGIMGPROC_OCROUTTYPE_RTF; + } + + if (0 == _stricmp(p, ".xls")) + { + return HGIMGPROC_OCROUTTYPE_XLS; + } + + if (0 == _stricmp(p, ".txt")) + { + return HGIMGPROC_OCROUTTYPE_TXT; + } + + if (0 == _stricmp(p, ".ofd")) + { + return HGIMGPROC_OCROUTTYPE_OFD; + } +#else + if (0 == strcasecmp(p, ".pdf")) + { + return HGIMGPROC_OCROUTTYPE_PDF; + } + + if (0 == strcasecmp(p, ".rtf")) + { + return HGIMGPROC_OCROUTTYPE_RTF; + } + + if (0 == strcasecmp(p, ".xls")) + { + return HGIMGPROC_OCROUTTYPE_XLS; + } + + if (0 == strcasecmp(p, ".txt")) + { + return HGIMGPROC_OCROUTTYPE_TXT; + } + + if (0 == strcasecmp(p, ".ofd")) + { + return HGIMGPROC_OCROUTTYPE_OFD; + } +#endif + + return 0; +} diff --git a/app/modules/imgproc/HGOCRBase.hpp b/app/modules/imgproc/HGOCRBase.hpp new file mode 100644 index 0000000..5003c53 --- /dev/null +++ b/app/modules/imgproc/HGOCRBase.hpp @@ -0,0 +1,25 @@ +#ifndef __HGOCRBASE_H__ +#define __HGOCRBASE_H__ + +#include "HGOCR.h" + +class HGOCRBase +{ +public: + HGOCRBase() {}; + virtual ~HGOCRBase() {}; + + virtual HGResult Init() = 0; + virtual HGResult Deinit() = 0; + virtual HGResult ImageOCR(HGImage image, class HGOCRRetImpl **ocrRet) = 0; + virtual HGResult ImageOCRToFile(HGImage image, HGUInt outType, const HGChar *outFileName) = 0; + virtual HGResult ImageTextDirectOCR(HGImage image, HGUInt* direct) = 0; + virtual HGResult AddToImageList(HGImage image) = 0; + virtual HGResult ClearImageList() = 0; + virtual HGResult ImageListOCRToFile(HGUInt outType, const HGChar* outFileName, HGImageListOcrFunc func, HGPointer param) = 0; + +protected: + static HGUInt GetOutTypeByFileName(const HGChar* fileName); +}; + +#endif /* __HGOCRBASE_H__ */ \ No newline at end of file diff --git a/app/modules/imgproc/HGOCRHanvon.cpp b/app/modules/imgproc/HGOCRHanvon.cpp new file mode 100644 index 0000000..112aaba --- /dev/null +++ b/app/modules/imgproc/HGOCRHanvon.cpp @@ -0,0 +1,475 @@ +#include "HGOCRHanvon.hpp" +#include "HGOCRRetImpl.hpp" +#include "../base/HGUtility.h" +#include "../base/HGInfo.h" +#include "../imgfmt/HGBmp.h" +#include "../imgfmt/HGJpeg.h" + +//HGUInt HGOCRHanvon::m_refCount = 0; +//HGOCRHanvon* HGOCRHanvon::m_OCR = NULL; + +HGOCRHanvon::HGOCRHanvon() +{ + m_dll = NULL; + m_ocrHandle = NULL; + m_imageList.clear(); + m_func = NULL; + m_param = NULL; + //m_FuncRet = 0; +} + +HGOCRHanvon::~HGOCRHanvon() +{ + +} + +HGResult HGOCRHanvon::Init() +{ + if (NULL != m_ocrHandle) + { + return HGBASE_ERR_FAIL; + } + + assert(NULL == m_dll); + + HGChar moduleName[256]; + HGBase_GetModuleName((void *)HGImgProc_CreateOCRMgr, moduleName, 256); + HGChar dllPath[256]; + HGBase_GetFilePath(moduleName, dllPath, 256); + +#if defined(HG_CMP_MSC) + strcat(dllPath, "hanwangOCRdetect.dll"); +#else + strcat(dllPath, "libhwocrdetect.so"); +#endif + HGResult ret = HGBase_CreateDll(dllPath, &m_dll); + if (HGBASE_ERR_OK != ret) + { + return ret; + } + + if (0 != HWOCR_SDKInitialize(&m_ocrHandle)) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRHanvon::Init: HWOCR_SDKInitialize fail"); + HGBase_DestroyDll(m_dll); + m_dll = NULL; + return HGIMGPROC_ERR_OCRINIT; + } + + //if (0 == m_refCount) + //{ + //HWOCR_InitPdf(); + //} + //++m_refCount; + + return HGBASE_ERR_OK; +} + +HGResult HGOCRHanvon::Deinit() +{ + if (NULL == m_ocrHandle) + { + return HGBASE_ERR_FAIL; + } + + ClearImageList(); + + //assert(0 != m_refCount); + //--m_refCount; + //if (0 == m_refCount) + //{ + //HWOCR_ExitPdf(); + //} + + HWOCR_SDKExit(m_ocrHandle); + m_ocrHandle = NULL; + + HGBase_DestroyDll(m_dll); + m_dll = NULL; + return HGBASE_ERR_OK; +} + +HGResult HGOCRHanvon::ImageOCR(HGImage image, class HGOCRRetImpl **ocrRet) +{ + if (NULL == image || NULL == ocrRet) + { + return HGBASE_ERR_INVALIDARG; + } + + HGChar tmpFileName[256]; + HGBase_GetTmpFileName("bmp", tmpFileName, 256); + HGResult ret = HGImgFmt_SaveBmpImage(image, NULL, tmpFileName); + if (HGBASE_ERR_OK != ret) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRHanvon::ImageOCR: HGImgFmt_SaveBmpImage fail %s", tmpFileName); + return ret; + } + + char* rst = NULL; + int len = 0; + int rc = HWOCR_RecognizeFile2Str((unsigned char*)tmpFileName, m_ocrHandle, &rst, &len); + HGBase_DeleteFile(tmpFileName); + if (0 != rc) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRHanvon::ImageOCR: HWOCR_RecognizeFile2Str fail in=%s", tmpFileName); + return HGIMGPROC_ERR_OCR; + } + + assert(NULL != rst && len > 0); + + std::vector blockInfo; + blockInfo.push_back(rst); + HWOCR_FreeStrRst(&rst); + + *ocrRet = new HGOCRRetImpl(blockInfo); + return HGBASE_ERR_OK; +} + +HGResult HGOCRHanvon::ImageOCRToFile(HGImage image, HGUInt outType, const HGChar *outFileName) +{ + if (NULL == image || outType > HGIMGPROC_OCROUTTYPE_OFD || NULL == outFileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == outType) + outType = GetOutTypeByFileName(outFileName); + + int fileType = -1; + if (HGIMGPROC_OCROUTTYPE_RTF == outType) + fileType = FILE_RTF; + else if (HGIMGPROC_OCROUTTYPE_XLS == outType) + fileType = FILE_XLS; + else if (HGIMGPROC_OCROUTTYPE_TXT == outType) + fileType = FILE_TXT; + else if (HGIMGPROC_OCROUTTYPE_PDF == outType) + fileType = FILE_PDF; + else if (HGIMGPROC_OCROUTTYPE_OFD == outType) + fileType = FILE_OFD; + if (-1 == fileType) + { + return HGBASE_ERR_INVALIDARG; + } + + HGChar tmpFileName[256]; + HGBase_GetTmpFileName("bmp", tmpFileName, 256); + HGResult ret = HGImgFmt_SaveBmpImage(image, NULL, tmpFileName); + if (HGBASE_ERR_OK != ret) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRHanvon::ImageOCRToFile: HGImgFmt_SaveBmpImage fail %s", tmpFileName); + return ret; + } + + HGChar tmpDir[256]; + HGBase_GetTmpFileName(NULL, tmpDir, 256); + ret = HGBase_CreateDir(tmpDir); + if (HGBASE_ERR_OK != ret) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRHanvon::ImageOCRToFile: HGBase_CreateDir fail %s", tmpDir); + HGBase_DeleteFile(tmpFileName); + return ret; + } + + int rc = HWOCR_RecognizeFile((unsigned char*)tmpFileName, (unsigned char*)outFileName, fileType, m_ocrHandle, NULL, tmpDir); + HGBase_DeleteDir(tmpDir); + HGBase_DeleteFile(tmpFileName); + if (0 != rc) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRHanvon::ImageOCR: HWOCR_RecognizeFile fail in=%s, out=%s, tmpdir=%s", + tmpFileName, outFileName, tmpDir); + return HGIMGPROC_ERR_OCR; + } + + return HGBASE_ERR_OK; +} + +HGResult HGOCRHanvon::ImageTextDirectOCR(HGImage image, HGUInt* direct) +{ + if (NULL == image || NULL == direct) + { + return HGBASE_ERR_INVALIDARG; + } + + HGChar tmpFileName[256]; + HGBase_GetTmpFileName("bmp", tmpFileName, 256); + HGResult ret = HGImgFmt_SaveBmpImage(image, NULL, tmpFileName); + if (HGBASE_ERR_OK != ret) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRHanvon::ImageTextDirectOCR: HGImgFmt_SaveBmpImage fail %s", tmpFileName); + return ret; + } + + int dire = -1; + int rc = HWOCR_GetFileDirect((unsigned char*)tmpFileName, m_ocrHandle, &dire); + HGBase_DeleteFile(tmpFileName); + if (0 != rc) + { + return HGIMGPROC_ERR_OCR; + } + + if (ROT0 == dire) + *direct = HGIMGPROC_OCRTEXTDIRECT_ORI; + else if (ROT90 == dire) + *direct = HGIMGPROC_OCRTEXTDIRECT_RIGHT; + else if (ROT180 == dire) + *direct = HGIMGPROC_OCRTEXTDIRECT_180; + else if (ROT270 == dire) + *direct = HGIMGPROC_OCRTEXTDIRECT_LEFT; + + return HGBASE_ERR_OK; +} + +HGResult HGOCRHanvon::AddToImageList(HGImage image) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + HGChar tmpFileName[256] = {0}; + HGBase_GetTmpFileName("jpg", tmpFileName, 256); + HGResult ret = HGImgFmt_SaveJpegImage(image, NULL, tmpFileName); + if (HGBASE_ERR_OK != ret) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRHanvon::AddToImageList: HGImgFmt_SaveJpegImage fail %s", tmpFileName); + return ret; + } + + m_imageList.push_back(tmpFileName); + return HGBASE_ERR_OK; +} + +HGResult HGOCRHanvon::ClearImageList() +{ + for (int i = 0; i < (int)m_imageList.size(); ++i) + { + HGBase_DeleteFile(m_imageList[i].c_str()); + } + + m_imageList.clear(); + return HGBASE_ERR_OK; +} + +HGResult HGOCRHanvon::ImageListOCRToFile(HGUInt outType, const HGChar* outFileName, HGImageListOcrFunc func, HGPointer param) +{ + if (m_imageList.empty()) + { + return HGBASE_ERR_FAIL; + } + + if (outType > HGIMGPROC_OCROUTTYPE_OFD || NULL == outFileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == outType) + outType = GetOutTypeByFileName(outFileName); + + int fileType = -1; + if (HGIMGPROC_OCROUTTYPE_RTF == outType) + fileType = FILE_RTF; + else if (HGIMGPROC_OCROUTTYPE_XLS == outType) + fileType = FILE_XLS; + else if (HGIMGPROC_OCROUTTYPE_TXT == outType) + fileType = FILE_TXT; + else if (HGIMGPROC_OCROUTTYPE_PDF == outType) + fileType = FILE_PDF; + else if (HGIMGPROC_OCROUTTYPE_OFD == outType) + fileType = FILE_OFD; + if (-1 == fileType) + { + return HGBASE_ERR_INVALIDARG; + } + + //m_OCR = this; + m_func = func; + m_param = param; + + HGChar** ppImageFiles = new HGChar* [m_imageList.size() + 1]; + for (int i = 0; i < (int)m_imageList.size(); ++i) + ppImageFiles[i] = (HGChar *)m_imageList[i].c_str(); + ppImageFiles[m_imageList.size()] = NULL; + + HGChar tmpDir[256]; + HGBase_GetTmpFileName(NULL, tmpDir, 256); + HGResult ret = HGBase_CreateDir(tmpDir); + if (HGBASE_ERR_OK == ret) + { +#if defined(HG_CMP_MSC) + int rc = HWOCR_RecognizeFileBatch(ppImageFiles, (unsigned char*)outFileName, fileType, m_ocrHandle, NULL, tmpDir, RecogProgress, IsCanceled); +#else + int rc = HWOCR_RecognizeFileBatch(ppImageFiles, (unsigned char*)outFileName, fileType, m_ocrHandle, NULL, tmpDir); +#endif + if (0 != rc) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRHanvon::ImageListOCRToFile: HWOCR_RecognizeFileBatch fail out=%s, tmpdir=%s", + outFileName, tmpDir); + ret = HGIMGPROC_ERR_OCR; + } + + HGBase_DeleteDir(tmpDir); + } + else + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRHanvon::ImageListOCRToFile: HGBase_CreateDir fail %s", tmpDir); + } + + delete[] ppImageFiles; + m_param = NULL; + m_func = NULL; + //m_OCR = NULL; + + // 不管成功与否都清空 + for (int i = 0; i < (int)m_imageList.size(); ++i) + { + HGBase_DeleteFile(m_imageList[i].c_str()); + } + m_imageList.clear(); + + return ret; +} + +int HGOCRHanvon::HWOCR_SDKInitialize(void** ppstOcrHandle) +{ + typedef int (*Func)(void**); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "HWOCR_SDKInitialize", (HGPointer *)&func); + if (NULL == func) + { + return -1; + } + + return func(ppstOcrHandle); +} + +void HGOCRHanvon::HWOCR_SDKExit(void* pstOcrHandle) +{ + typedef void (*Func)(void*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "HWOCR_SDKExit", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(pstOcrHandle); +} + +void HGOCRHanvon::HWOCR_InitPdf() +{ + typedef void (*Func)(); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "HWOCR_InitPdf", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(); +} + +void HGOCRHanvon::HWOCR_ExitPdf() +{ + typedef void (*Func)(); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "HWOCR_ExitPdf", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(); +} + +int HGOCRHanvon::HWOCR_RecognizeFile2Str(unsigned char* ImgFile, void* pstHandle, char** ppRst, int* pnLen) +{ + typedef int (*Func)(unsigned char*, void*, char**, int*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "HWOCR_RecognizeFile2Str", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(ImgFile, pstHandle, ppRst, pnLen); +} + +void HGOCRHanvon::HWOCR_FreeStrRst(char** ppRst) +{ + typedef void (*Func)(char**); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "HWOCR_FreeStrRst", (HGPointer*)&func); + if (NULL == func) + { + return; + } + + func(ppRst); +} + +int HGOCRHanvon::HWOCR_RecognizeFile(unsigned char* ImgFile, unsigned char* OutFile, int nFileType, void* pstHandle, char* pLibDir, char* pTmpDir) +{ + typedef int (*Func)(unsigned char*, unsigned char*, int, void*, char*, char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "HWOCR_RecognizeFile", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(ImgFile, OutFile, nFileType, pstHandle, pLibDir, pTmpDir); +} + +int HGOCRHanvon::HWOCR_GetFileDirect(unsigned char* ImgFile, void* pstHandle, int* pDirect) +{ + typedef int (*Func)(unsigned char*, void *, int *); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "HWOCR_GetFileDirect", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(ImgFile, pstHandle, pDirect); +} + +#if defined(HG_CMP_MSC) +int HGOCRHanvon::HWOCR_RecognizeFileBatch(char** ppImageFiles, unsigned char* OutFile, int nFileType, void* pstHandle, char* pLibDir, char* pTmpDir, + HWOCR_RecogProgress aFuncRecogProgress, HWOCR_IsCanceled aFuncIsCanceled) +{ + typedef int (*Func)(char**, unsigned char*, int, void*, char*, char*, HWOCR_RecogProgress, HWOCR_IsCanceled); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "HWOCR_RecognizeFileBatch", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(ppImageFiles, OutFile, nFileType, pstHandle, pLibDir, pTmpDir, aFuncRecogProgress, aFuncIsCanceled); +} +#else +int HGOCRHanvon::HWOCR_RecognizeFileBatch(char** ppImageFiles, unsigned char* OutFile, int nFileType, void* pstHandle, char* pLibDir, char* pTmpDir) +{ + typedef int (*Func)(char**, unsigned char*, int, void*, char*, char*); + Func func = NULL; + HGBase_GetDllProcAddress(m_dll, "HWOCR_RecognizeFileBatch", (HGPointer*)&func); + if (NULL == func) + { + return -1; + } + + return func(ppImageFiles, OutFile, nFileType, pstHandle, pLibDir, pTmpDir); +} +#endif + +#if defined(HG_CMP_MSC) +int HGOCRHanvon::RecogProgress(int nPercent) +{ + return 0; +} + +int HGOCRHanvon::IsCanceled() +{ + return 0; +} +#endif diff --git a/app/modules/imgproc/HGOCRHanvon.hpp b/app/modules/imgproc/HGOCRHanvon.hpp new file mode 100644 index 0000000..8cfb4fd --- /dev/null +++ b/app/modules/imgproc/HGOCRHanvon.hpp @@ -0,0 +1,60 @@ +#ifndef __HGOCRHANVON_HPP__ +#define __HGOCRHANVON_HPP__ + +#include "HGOCRBase.hpp" +#include "../base/HGDef.h" +#include "../base/HGInc.h" +#include "../base/HGImage.h" +#include "../base/HGDll.h" +#include "hanwangOCRdetect.h" +#include +#include + +class HGOCRHanvon : public HGOCRBase +{ +public: + HGOCRHanvon(); + virtual ~HGOCRHanvon(); + + HGResult Init(); + HGResult Deinit(); + HGResult ImageOCR(HGImage image, class HGOCRRetImpl **ocrRet); + HGResult ImageOCRToFile(HGImage image, HGUInt outType, const HGChar *outFileName); + HGResult ImageTextDirectOCR(HGImage image, HGUInt* direct); + HGResult AddToImageList(HGImage image); + HGResult ClearImageList(); + HGResult ImageListOCRToFile(HGUInt outType, const HGChar* outFileName, HGImageListOcrFunc func, HGPointer param); + +private: + int HWOCR_SDKInitialize(void** ppstOcrHandle); + void HWOCR_SDKExit(void* pstOcrHandle); + void HWOCR_InitPdf(); + void HWOCR_ExitPdf(); + int HWOCR_RecognizeFile2Str(unsigned char* ImgFile, void* pstHandle, char** ppRst, int* pnLen); + void HWOCR_FreeStrRst(char** ppRst); + int HWOCR_RecognizeFile(unsigned char* ImgFile, unsigned char* OutFile, int nFileType, void* pstHandle, char* pLibDir, char* pTmpDir); + int HWOCR_GetFileDirect(unsigned char* ImgFile, void* pstHandle, int* pDirect); +#if defined(HG_CMP_MSC) + int HWOCR_RecognizeFileBatch(char** ppImageFiles, unsigned char* OutFile, int nFileType, void* pstHandle, char* pLibDir, char* pTmpDir, + HWOCR_RecogProgress aFuncRecogProgress, HWOCR_IsCanceled aFuncIsCanceled); +#else + int HWOCR_RecognizeFileBatch(char** ppImageFiles, unsigned char* OutFile, int nFileType, void* pstHandle, char* pLibDir, char* pTmpDir); +#endif + +#if defined(HG_CMP_MSC) + static int RecogProgress(int nPercent); + static int IsCanceled(); +#endif + +private: + //static HGUInt m_refCount; + //static HGOCRHanvon* m_OCR; + HGDll m_dll; + void* m_ocrHandle; + std::vector m_imageList; + HGImageListOcrFunc m_func; + HGPointer m_param; + //HGInt m_FuncRet; +}; + +#endif /* __HGOCRHANVON_HPP__ */ \ No newline at end of file diff --git a/app/modules/imgproc/HGOCRRetImpl.cpp b/app/modules/imgproc/HGOCRRetImpl.cpp new file mode 100644 index 0000000..3a0c2b9 --- /dev/null +++ b/app/modules/imgproc/HGOCRRetImpl.cpp @@ -0,0 +1,33 @@ +#include "HGOCRRetImpl.hpp" + +HGOCRRetImpl::HGOCRRetImpl(const std::vector& blockInfo) +{ + m_blockInfo = blockInfo; +} + +HGOCRRetImpl::~HGOCRRetImpl() +{ + +} + +HGResult HGOCRRetImpl::GetBlockCount(HGUInt* count) +{ + if (NULL == count) + { + return HGBASE_ERR_INVALIDARG; + } + + *count = (HGUInt)m_blockInfo.size(); + return HGBASE_ERR_OK; +} + +HGResult HGOCRRetImpl::GetBlockText(HGUInt index, const HGChar** text) +{ + if (index < 0 || index >= (HGUInt)m_blockInfo.size() || NULL == text) + { + return HGBASE_ERR_INVALIDARG; + } + + *text = m_blockInfo[index].c_str(); + return HGBASE_ERR_OK; +} \ No newline at end of file diff --git a/app/modules/imgproc/HGOCRRetImpl.hpp b/app/modules/imgproc/HGOCRRetImpl.hpp new file mode 100644 index 0000000..53e2269 --- /dev/null +++ b/app/modules/imgproc/HGOCRRetImpl.hpp @@ -0,0 +1,22 @@ +#ifndef __HGOCRRETIMPL_HPP__ +#define __HGOCRRETIMPL_HPP__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include +#include + +class HGOCRRetImpl +{ +public: + HGOCRRetImpl(const std::vector &blockInfo); + ~HGOCRRetImpl(); + + HGResult GetBlockCount(HGUInt *count); + HGResult GetBlockText(HGUInt index, const HGChar** text); + +private: + std::vector m_blockInfo; +}; + +#endif /* __HGOCRRETIMPL_HPP__ */ \ No newline at end of file diff --git a/app/modules/imgproc/HGOCRTesseract.cpp b/app/modules/imgproc/HGOCRTesseract.cpp new file mode 100644 index 0000000..b8f14b3 --- /dev/null +++ b/app/modules/imgproc/HGOCRTesseract.cpp @@ -0,0 +1,336 @@ +#include "HGOCRTesseract.hpp" +#include "HGOCR.h" +#include "HGOCRRetImpl.hpp" +#include "HGOCRRetImpl.hpp" +#include "../base/HGUtility.h" +#include "../base/HGInfo.h" +#include "../imgfmt/HGBmp.h" +#include "../imgfmt/HGJpeg.h" +#include "HGString.h" + +HGOCRTesseract::HGOCRTesseract() +{ + m_baseApi = NULL; + m_tiffFileName.clear(); + m_tiffWriter = NULL; +} + +HGOCRTesseract::~HGOCRTesseract() +{ + +} + +HGResult HGOCRTesseract::Init() +{ + if (NULL != m_baseApi) + { + return HGBASE_ERR_FAIL; + } + + m_baseApi = TessBaseAPICreate(); + if (NULL == m_baseApi) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRTesseract::Init: TessBaseAPICreate fail"); + return HGIMGPROC_ERR_OCRINIT; + } + + HGChar moduleName[256]; + HGBase_GetModuleName((void*)HGImgProc_CreateOCRMgr, moduleName, 256); + HGChar dataPath[256]; + HGBase_GetFilePath(moduleName, dataPath, 256); + strcat(dataPath, "tessdata"); + + int rc = TessBaseAPIInit3(m_baseApi, dataPath, "chi_sim"); + if (0 != rc) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRTesseract::Init: TessBaseAPIInit3 fail"); + TessBaseAPIDelete(m_baseApi); + m_baseApi = NULL; + return HGIMGPROC_ERR_OCRINIT; + } + + TessBaseAPISetPageSegMode(m_baseApi, TessPageSegMode::PSM_AUTO_OSD); + return HGBASE_ERR_OK; +} + +HGResult HGOCRTesseract::Deinit() +{ + if (NULL == m_baseApi) + { + return HGBASE_ERR_FAIL; + } + + ClearImageList(); + + TessBaseAPIDelete(m_baseApi); + m_baseApi = NULL; + return HGBASE_ERR_OK; +} + +HGResult HGOCRTesseract::ImageOCR(HGImage image, class HGOCRRetImpl** ocrRet) +{ + if (NULL == image || NULL == ocrRet) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImage image2 = NULL; + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_RGB != imgInfo.type || HGBASE_IMGORIGIN_TOP != imgInfo.origin) + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + return ret; + } + else + { + image2 = image; + } + + HGBase_GetImageInfo(image2, &imgInfo); + HGByte* imageData = NULL; + HGBase_GetImageData(image2, &imageData); + + TessBaseAPISetImage(m_baseApi, imageData, imgInfo.width, imgInfo.height, 3, imgInfo.widthStep); + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(image2, &xDpi, &yDpi); + TessBaseAPISetSourceResolution(m_baseApi, (xDpi + yDpi) / 2); + + char *text = TessBaseAPIGetUTF8Text(m_baseApi); + if (NULL == text) + { + if (image2 != image) + HGBase_DestroyImage(image2); + return HGIMGPROC_ERR_OCR; + } + + std::vector blockInfo; + blockInfo.push_back(Utf8ToStdString(text)); + *ocrRet = new HGOCRRetImpl(blockInfo); + + TessDeleteText(text); + if (image2 != image) + HGBase_DestroyImage(image2); + return HGBASE_ERR_OK; +} + +HGResult HGOCRTesseract::ImageOCRToFile(HGImage image, HGUInt outType, const HGChar* outFileName) +{ + if (NULL == image || outType > HGIMGPROC_OCROUTTYPE_OFD || NULL == outFileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == outType) + outType = GetOutTypeByFileName(outFileName); + + HGChar tmpFileName[256]; + HGBase_GetTmpFileName("bmp", tmpFileName, 256); + HGResult ret = HGImgFmt_SaveBmpImage(image, NULL, tmpFileName); + if (HGBASE_ERR_OK != ret) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRTesseract::ImageOCRToFile: HGImgFmt_SaveBmpImage fail %s", tmpFileName); + return ret; + } + + ret = OCRToFile(tmpFileName, outType, outFileName); + HGBase_DeleteFile(tmpFileName); + return ret; +} + +HGResult HGOCRTesseract::ImageTextDirectOCR(HGImage image, HGUInt* direct) +{ + if (NULL == image || NULL == direct) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImage image2 = NULL; + + HGImageInfo imgInfo; + HGBase_GetImageInfo(image, &imgInfo); + if (HGBASE_IMGTYPE_RGB != imgInfo.type || HGBASE_IMGORIGIN_TOP != imgInfo.origin) + { + HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); + if (HGBASE_ERR_OK != ret) + return ret; + } + else + { + image2 = image; + } + + HGBase_GetImageInfo(image2, &imgInfo); + HGByte* imageData = NULL; + HGBase_GetImageData(image2, &imageData); + + TessBaseAPISetImage(m_baseApi, imageData, imgInfo.width, imgInfo.height, 3, imgInfo.widthStep); + HGUInt xDpi, yDpi; + HGBase_GetImageDpi(image2, &xDpi, &yDpi); + TessBaseAPISetSourceResolution(m_baseApi, (xDpi + yDpi) / 2); + + TessPageIterator* iter = TessBaseAPIAnalyseLayout(m_baseApi); + if (NULL == iter) + { + if (image2 != image) + HGBase_DestroyImage(image2); + return HGIMGPROC_ERR_OCR; + } + + TessOrientation orientation; + TessWritingDirection writing_direction; + TessTextlineOrder textline_order; + float deskew_angle; + TessPageIteratorOrientation(iter, &orientation, &writing_direction, &textline_order, &deskew_angle); + + if (TessOrientation::ORIENTATION_PAGE_UP == orientation) + *direct = HGIMGPROC_OCRTEXTDIRECT_ORI; + else if (TessOrientation::ORIENTATION_PAGE_RIGHT == orientation) + *direct = HGIMGPROC_OCRTEXTDIRECT_RIGHT; + else if (TessOrientation::ORIENTATION_PAGE_DOWN == orientation) + *direct = HGIMGPROC_OCRTEXTDIRECT_180; + else if (TessOrientation::ORIENTATION_PAGE_LEFT == orientation) + *direct = HGIMGPROC_OCRTEXTDIRECT_LEFT; + + TessPageIteratorDelete(iter); + if (image2 != image) + HGBase_DestroyImage(image2); + return HGBASE_ERR_OK; +} + +HGResult HGOCRTesseract::AddToImageList(HGImage image) +{ + if (NULL == image) + { + return HGBASE_ERR_INVALIDARG; + } + + if (NULL == m_tiffWriter) + { + HGChar tmpFileName[256] = { 0 }; + HGBase_GetTmpFileName("tif", tmpFileName, 256); + m_tiffFileName = tmpFileName; + + HGResult ret = HGImgFmt_OpenTiffWriter(m_tiffFileName.c_str(), &m_tiffWriter); + if (HGBASE_ERR_OK != ret) + { + HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGOCRTesseract::AddToImageList: HGImgFmt_OpenTiffWriter fail %s", m_tiffFileName.c_str()); + m_tiffFileName.clear(); + return ret; + } + } + + return HGImgFmt_SaveImageToTiffWriter(m_tiffWriter, image, NULL); +} + +HGResult HGOCRTesseract::ClearImageList() +{ + if (NULL != m_tiffWriter) + { + HGImgFmt_CloseTiffWriter(m_tiffWriter); + m_tiffWriter = NULL; + HGBase_DeleteFile(m_tiffFileName.c_str()); + m_tiffFileName.clear(); + } + + return HGBASE_ERR_OK; +} + +HGResult HGOCRTesseract::ImageListOCRToFile(HGUInt outType, const HGChar* outFileName, HGImageListOcrFunc func, HGPointer param) +{ + if (NULL == m_tiffWriter) + { + return HGBASE_ERR_FAIL; + } + + if (outType > HGIMGPROC_OCROUTTYPE_OFD || NULL == outFileName) + { + return HGBASE_ERR_INVALIDARG; + } + + if (0 == outType) + outType = GetOutTypeByFileName(outFileName); + + if (HGIMGPROC_OCROUTTYPE_PDF != outType && HGIMGPROC_OCROUTTYPE_TXT != outType) + { + return HGBASE_ERR_INVALIDARG; + } + + HGImgFmt_CloseTiffWriter(m_tiffWriter); + m_tiffWriter = NULL; + assert(!m_tiffFileName.empty()); + HGResult ret = OCRToFile(m_tiffFileName.c_str(), outType, outFileName); + HGBase_DeleteFile(m_tiffFileName.c_str()); + m_tiffFileName.clear(); + return ret; +} + +HGResult HGOCRTesseract::OCRToFile(const HGChar* inFileName, HGUInt outType, const HGChar* outFileName) +{ + assert(NULL != inFileName); + assert(NULL != outFileName); + + HGResult ret = HGBASE_ERR_NOTSUPPORT; + if (HGIMGPROC_OCROUTTYPE_PDF == outType) + { + HGChar outputbase[256] = { 0 }; + const char* p = strrchr(outFileName, '.'); + if (NULL != p && 0 == strcmp(p, ".pdf")) + memcpy(outputbase, outFileName, p - outFileName); + else + strcpy(outputbase, outFileName); + + ret = HGIMGPROC_ERR_OCR; + TessResultRenderer* pdfRender = TessPDFRendererCreate(outputbase, TessBaseAPIGetDatapath(m_baseApi), FALSE); + if (NULL != pdfRender) + { + if (TessBaseAPIProcessPages(m_baseApi, inFileName, NULL, 0, pdfRender)) + ret = HGBASE_ERR_OK; + TessDeleteResultRenderer(pdfRender); + + if (HGBASE_ERR_OK == ret) + { + HGChar destFileName[256]; + sprintf(destFileName, "%s.pdf", outputbase); +#if defined(HG_CMP_MSC) + MoveFileA(destFileName, outFileName); +#else + rename(destFileName, outFileName); +#endif + } + } + } + else if (HGIMGPROC_OCROUTTYPE_TXT == outType) + { + HGChar outputbase[256] = { 0 }; + const char* p = strrchr(outFileName, '.'); + if (NULL != p && 0 == strcmp(p, ".txt")) + memcpy(outputbase, outFileName, p - outFileName); + else + strcpy(outputbase, outFileName); + + ret = HGIMGPROC_ERR_OCR; + TessResultRenderer* txtRender = TessTextRendererCreate(outputbase); + if (NULL != txtRender) + { + if (TessBaseAPIProcessPages(m_baseApi, inFileName, NULL, 0, txtRender)) + ret = HGBASE_ERR_OK; + TessDeleteResultRenderer(txtRender); + + if (HGBASE_ERR_OK == ret) + { + HGChar destFileName[256]; + sprintf(destFileName, "%s.txt", outputbase); +#if defined(HG_CMP_MSC) + MoveFileA(destFileName, outFileName); +#else + rename(destFileName, outFileName); +#endif + } + } + } + + return ret; +} \ No newline at end of file diff --git a/app/modules/imgproc/HGOCRTesseract.hpp b/app/modules/imgproc/HGOCRTesseract.hpp new file mode 100644 index 0000000..82e1333 --- /dev/null +++ b/app/modules/imgproc/HGOCRTesseract.hpp @@ -0,0 +1,38 @@ +#ifndef __HGOCRTESSERACT_HPP__ +#define __HGOCRTESSERACT_HPP__ + +#include "HGOCRBase.hpp" +#include "../base/HGDef.h" +#include "../base/HGInc.h" +#include "../base/HGImage.h" +#include "../base/HGDll.h" +#include "../imgfmt/HGTiff.h" +#include "tesseract/capi.h" +#include +#include + +class HGOCRTesseract : public HGOCRBase +{ +public: + HGOCRTesseract(); + virtual ~HGOCRTesseract(); + + HGResult Init(); + HGResult Deinit(); + HGResult ImageOCR(HGImage image, class HGOCRRetImpl** ocrRet); + HGResult ImageOCRToFile(HGImage image, HGUInt outType, const HGChar* outFileName); + HGResult ImageTextDirectOCR(HGImage image, HGUInt* direct); + HGResult AddToImageList(HGImage image); + HGResult ClearImageList(); + HGResult ImageListOCRToFile(HGUInt outType, const HGChar* outFileName, HGImageListOcrFunc func, HGPointer param); + +private: + HGResult OCRToFile(const HGChar *inFileName, HGUInt outType, const HGChar* outFileName); + +private: + TessBaseAPI* m_baseApi; + std::string m_tiffFileName; + HGTiffWriter m_tiffWriter; +}; + +#endif /* __HGOCRTESSERACT_HPP__ */ \ No newline at end of file diff --git a/app/modules/imgproc/ImageProcess/ImageApply.cpp b/app/modules/imgproc/ImageProcess/ImageApply.cpp new file mode 100644 index 0000000..83d6f16 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApply.cpp @@ -0,0 +1,9 @@ +#include "ImageApply.h" + +CImageApply::CImageApply(void) +{ +} + +CImageApply::~CImageApply(void) +{ +} diff --git a/app/modules/imgproc/ImageProcess/ImageApply.h b/app/modules/imgproc/ImageProcess/ImageApply.h new file mode 100644 index 0000000..464c3e2 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApply.h @@ -0,0 +1,33 @@ +/* + * ==================================================== + + * 功能:所有图像处理功能类的基类 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 + * 版本号:v1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_H +#define IMAGE_APPLY_H + +#include +#include +#include + +class CImageApply +{ +public: + CImageApply(void); + virtual ~CImageApply(void); + + virtual void apply(cv::Mat& pDib,int side) = 0; + + virtual void apply(std::vector& mats, bool isTwoSide) = 0; +}; + +typedef std::shared_ptr ImageApplyPtr; + +#endif // !IMAGE_APPLY_H diff --git a/app/modules/imgproc/ImageProcess/ImageApplyAdjustColors.cpp b/app/modules/imgproc/ImageProcess/ImageApplyAdjustColors.cpp new file mode 100644 index 0000000..588cb39 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyAdjustColors.cpp @@ -0,0 +1,90 @@ +#include "ImageApplyAdjustColors.h" + +CImageApplyAdjustColors::CImageApplyAdjustColors(void) + : m_brightness(0) + , m_contrast(0) + , m_gamma(1.0f) + , lut(1, 256, CV_8UC1) +{ + update_lutData(); +} + +CImageApplyAdjustColors::CImageApplyAdjustColors(int brightness, int contrast, float gamma) + : lut(1, 256, CV_8UC1) +{ + setAdjustColors(brightness, contrast, gamma); +} + +CImageApplyAdjustColors::~CImageApplyAdjustColors(void) +{ + +} + +void CImageApplyAdjustColors::apply(cv::Mat& pDib,int side) +{ + (void)side; + if (pDib.empty()) return; + + if (m_brightness != 0 || m_contrast != 0 || m_gamma < 0.999999f || m_gamma > 1.000001f) + cv::LUT(pDib, lut, pDib); +} + +void CImageApplyAdjustColors::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if(!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyAdjustColors::setAdjustColors(int brightness, int contrast, float gamma) +{ + m_brightness = cv::max(-255, cv::min(brightness, 255)); + m_contrast = cv::max(-127, cv::min(contrast, 127)); + m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f)); + update_lutData(); +} + +void CImageApplyAdjustColors::setBrightness(int brightness) +{ + m_brightness = cv::max(-255, cv::min(brightness, 255)); + update_lutData(); +} + +void CImageApplyAdjustColors::setContrast(int contrast) +{ + m_contrast = cv::max(-127, cv::min(contrast, 127)); + update_lutData(); +} + +void CImageApplyAdjustColors::setGamma(float gamma) +{ + m_gamma = cv::max(0.1f, cv::min(gamma, 5.0f)); + update_lutData(); +} + +void CImageApplyAdjustColors::update_lutData() +{ + unsigned char* ptr = lut.data; + //update gamma + + for (int i = 0; i < 256; i++) + { + //update brightness + ptr[i] = static_cast(cv::max(0, cv::min(i + m_brightness, 255))); + + //update contrast + if (ptr[i] < 128) + ptr[i] = static_cast(cv::max(0, cv::min(ptr[i] - m_contrast, 127))); + else + ptr[i] = static_cast(cv::max(127, cv::min(ptr[i] + m_contrast, 255))); + } + float g = 1.0f / m_gamma; + for (int i = 0; i < 256; i++) + ptr[i] = static_cast(cv::min(255, static_cast(cv::pow(static_cast(ptr[i]) / 255.0f, g) * 255.0f + 0.5f))); +} diff --git a/app/modules/imgproc/ImageProcess/ImageApplyAdjustColors.h b/app/modules/imgproc/ImageProcess/ImageApplyAdjustColors.h new file mode 100644 index 0000000..3004514 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyAdjustColors.h @@ -0,0 +1,65 @@ +/* + * ==================================================== + + * 功能:色彩调整,可以调整伽马、亮度、对比度效果。叠加优先级:亮度 > 对比度 > 伽马 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 + * 版本号:v1.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_ADJUST_COLOR_H +#define IMAGE_APPLY_ADJUST_COLOR_H + +#include "ImageApply.h" + +class CImageApplyAdjustColors : public CImageApply +{ +public: + + CImageApplyAdjustColors(void); + + /* + * brightness [in]: 亮度调节,取值范围[-255, 255] + * constrast [in]: 对比度调节,取值范围[-128, 127] + * gamma [in]: 伽马调节,取值范围[0.1, 5.0] + */ + CImageApplyAdjustColors(int brightness, int contrast, float gamma); + + virtual ~CImageApplyAdjustColors(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + void setAdjustColors(int brightness, int contrast, float gamma); + + int getContrast() { return m_contrast; } + + int getBrightness() { return m_brightness; } + + double getGamma() { return m_gamma; } + + void setBrightness(int brightness); + + void setContrast(int contrast); + + void setGamma(float gamma); + +private: + + void update_lutData(); + +private: + + int m_brightness; + int m_contrast; + float m_gamma; + cv::Mat lut; +}; + +#endif // !IMAGE_APPLY_ADJUST_COLOR_H + + diff --git a/app/modules/imgproc/ImageProcess/ImageApplyAutoCrop.cpp b/app/modules/imgproc/ImageProcess/ImageApplyAutoCrop.cpp new file mode 100644 index 0000000..4cfda9d --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyAutoCrop.cpp @@ -0,0 +1,330 @@ +#include "ImageApplyAutoCrop.h" +#include "ImageProcess_Public.h" +#include +#include +#include "ImageApplyDispersion.h" + +CImageApplyAutoCrop::CImageApplyAutoCrop() + : m_isCrop(false) + , m_isDesaskew(false) + , m_isFillBlank(false) + , m_isConvexHull(true) + , m_isFillColor(false) + , m_threshold(40) + , m_noise(8) + , m_indent(5) + , m_normalCrop(false) + , m_isDispersion(true) +{ +} + +CImageApplyAutoCrop::CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex, bool isFillColor, + double threshold, int noise, int indent, bool normalCrop, bool dispersion) + : m_isCrop(isCrop) + , m_isDesaskew(isDesaskew) + , m_isFillBlank(isFillBlank) + , m_isConvexHull(isConvex) + , m_isFillColor(isFillColor) + , m_threshold(threshold) + , m_noise(noise) + , m_indent(indent) + , m_fixedSize(fixedSize) + , m_normalCrop(normalCrop) + , m_isDispersion(dispersion) +{ +} + +CImageApplyAutoCrop::~CImageApplyAutoCrop() +{ +} + +void CImageApplyAutoCrop::apply(cv::Mat& pDib, int side) +{ + cv::Mat dst; + autoCrop_desaskew_fillBlank(pDib, dst, m_isCrop, m_isDesaskew, m_isFillBlank, m_fixedSize.width, m_fixedSize.height, + m_isConvexHull, m_isFillColor, m_threshold, m_noise, m_indent, m_normalCrop, m_isDispersion); + pDib = dst; +} + +void CImageApplyAutoCrop::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +#define FRONT_TOP 70 +#define FX_FY 0.5f + +void myWarpAffine(cv::InputArray _src, cv::OutputArray _dst, cv::InputArray _M0, cv::Size dsize, int flags, int borderType, const cv::Scalar& borderValue) +{ + int interpolation = flags; + cv::Mat src = _src.getMat(), M0 = _M0.getMat(); + cv::Mat dst = _dst.getMat(); + + if (dst.data == src.data) + src = src.clone(); + + double M[6] = { 0 }; + cv::Mat matM(2, 3, CV_64F, M); + if (interpolation == cv::INTER_AREA) + interpolation = cv::INTER_LINEAR; + + M0.convertTo(matM, matM.type()); + + if (!(flags & cv::WARP_INVERSE_MAP)) + { + double D = M[0] * M[4] - M[1] * M[3]; + D = D != 0 ? 1. / D : 0; + double A11 = M[4] * D, A22 = M[0] * D; + M[0] = A11; M[1] *= -D; + M[3] *= -D; M[4] = A22; + double b1 = -M[0] * M[2] - M[1] * M[5]; + double b2 = -M[3] * M[2] - M[4] * M[5]; + M[2] = b1; M[5] = b2; + } + + cv::hal::warpAffine(src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows, + M, interpolation, borderType, borderValue.val); +} + +uchar getBackGroudChannelMean(const cv::Mat& gray, int total, int threshold) +{ + cv::Mat image_clone; + cv::resize(gray, image_clone, cv::Size(), 0.25, 0.25); + + int threnshold = total / 32; + int channels[] = { 0 }; + int nHistSize[] = { 256 }; + float range[] = { 0, 256 }; + const float* fHistRanges[] = { range }; + cv::Mat hist; + cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, nHistSize, fHistRanges, true, false); + + int hist_array[256]; + for (int i = 0; i < 256; i++) + hist_array[i] = hist.at(i, 0); + + int length = 1; + const int length_max = 255 - threshold; + while (length < length_max) + { + for (int i = threshold + 1; i < 256 - length; i++) + { + int count = 0; + uint pixSum = 0; + for (int j = 0; j < length; j++) + { + count += hist_array[j + i]; + pixSum += hist_array[j + i] * (i + j); + } + + if (count >= threnshold) + return pixSum / count; + } + length++; + } + return 255; +} + +cv::Scalar getBackGroudColor(const cv::Mat& image, int total, int threshold) +{ + if (image.channels() == 3) + { + cv::Mat image_bgr[3]; + cv::split(image, image_bgr); + + uchar bgr[3]; + for (size_t i = 0; i < 3; i++) + bgr[i] = getBackGroudChannelMean(image_bgr[i], total, threshold); + return cv::Scalar(bgr[0], bgr[1], bgr[2]); + } + else + return cv::Scalar::all(getBackGroudChannelMean(image, total, threshold)); +} + +CImageApplyDispersion dispersion_apply; +#define COLOR_SCALE_THRE 0.5 +void autoCrop_desaskew_fillBlank(const cv::Mat& src, cv::Mat& dst, bool isAutoCrop, bool isDesaskew, bool isFillBlank, int dWidth, int dHeight, + bool isConvex, bool isColorBlank, double threshold, int noise, int indent, bool isNormalCrop, bool dispersion) +{ + if (src.empty()) return; + + if (isNormalCrop) + { + cv::Rect roi = cv::Rect((src.cols - dWidth) / 2, FRONT_TOP, dWidth, dHeight) & cv::Rect(0, 0, src.cols, src.rows); + dst = src(roi).clone(); + return; + } + + if (!isAutoCrop && !isDesaskew && !isFillBlank && (dWidth <= 0 || dHeight <= 0)) + { + dst = src.clone(); + return; + } + + cv::Mat resizeMat; + cv::Mat thre; + + cv::resize(src, resizeMat, cv::Size(), FX_FY, FX_FY, cv::INTER_NEAREST); + hg::threshold_Mat(resizeMat, thre, threshold); + + if (noise > 0) + cv::morphologyEx(thre, thre, cv::MORPH_OPEN, getStructuringElement(cv::MORPH_RECT, cv::Size(noise * FX_FY, 1)), + cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + + std::vector hierarchy; + std::vector> contours; + + hg::findContours(thre, contours, hierarchy, cv::RETR_EXTERNAL); + + for (std::vector& sub : contours) + for (cv::Point& p : sub) + p /= FX_FY; + + std::vector maxContour = hg::getMaxContour(contours, hierarchy); + + if (maxContour.empty()) + { + if (isAutoCrop) + dst = src.clone(); + else + { + cv::Rect roi = cv::Rect((src.cols - dWidth) / 2, FRONT_TOP, dWidth, dHeight) & cv::Rect(0, 0, src.cols, src.rows); + dst = src(roi).clone(); + } + return; + } + + cv::RotatedRect rect = hg::getBoundingRect(maxContour); + + if (dispersion) + { + cv::Mat mat_dispersion = src(cv::boundingRect(maxContour)); + dispersion_apply.apply(mat_dispersion, 0); + } + + cv::Scalar blankColor; + if (isFillBlank) + if (isColorBlank) + blankColor = getBackGroudColor(resizeMat, rect.size.area() * FX_FY * FX_FY, COLOR_SCALE_THRE); + else + blankColor = cv::Scalar::all(255); + else + blankColor = cv::Scalar::all(0); + + if (isAutoCrop) + if (isDesaskew) + dst = cv::Mat(cv::Size(rect.size), src.type(), blankColor); + else + dst = cv::Mat(rect.boundingRect().size(), src.type(), blankColor); + else + dst = cv::Mat(dHeight, dWidth, src.type(), blankColor); + + cv::Mat dstROI; + if (isDesaskew && rect.angle != 0) + { + cv::Point2f srcTri[4], dstTri[3]; + rect.points(srcTri); + srcTri[0].x -= 1; + srcTri[1].x -= 1; + srcTri[2].x -= 1; + + int w = rect.size.width; + int h = rect.size.height; + int x = (dst.cols - w) / 2; + int y = (dst.rows - h) / 2; + dstTri[0] = cv::Point2f(0, h); + dstTri[1] = cv::Point2f(0, 0); + dstTri[2] = cv::Point2f(w, 0); + + dstROI = dst(cv::Rect(x, y, w, h) & cv::Rect(0, 0, dst.cols, dst.rows)); + myWarpAffine(src, dstROI, cv::getAffineTransform(srcTri, dstTri), dstROI.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + } + else + { + cv::Rect bounding = cv::boundingRect(maxContour); + + if (bounding.width > dst.cols) + { + bounding.x += (bounding.width - dst.cols) / 2; + bounding.width = dst.cols; + } + + if (bounding.height > dst.rows) + { + bounding.y += (bounding.height - dst.rows) / 2; + bounding.height = dst.rows; + } + + dstROI = dst(cv::Rect((dst.cols - bounding.width) / 2, (dst.rows - bounding.height) / 2, bounding.width, bounding.height)); + src(bounding).copyTo(dstROI); + } + + if (isFillBlank) + { + if (isConvex) + { + hg::convexHull(maxContour, maxContour); + contours.clear(); + contours.push_back(maxContour); + } + + cv::Point2f srcTri[4], dstTri[3]; + int w, h; + if (isDesaskew && rect.angle != 0) + { + rect.points(srcTri); + srcTri[0].x -= 1; + srcTri[1].x -= 1; + srcTri[2].x -= 1; + w = rect.size.width; + h = rect.size.height; + } + else + { + cv::Rect bounding = rect.boundingRect(); + srcTri[0] = cv::Point(bounding.x, bounding.br().y - 1); + srcTri[1] = cv::Point(bounding.x, bounding.y); + srcTri[2] = cv::Point(bounding.br().x - 1, bounding.y); + w = bounding.width; + h = bounding.height; + } + + dstTri[0] = cv::Point2f((dstROI.cols - w) / 2 + indent, (dstROI.rows - h) / 2 + h - indent); + dstTri[1] = cv::Point2f((dstROI.cols - w) / 2 + indent, (dstROI.rows - h) / 2 + indent); + dstTri[2] = cv::Point2f((dstROI.cols - w) / 2 - indent + w, (dstROI.rows - h) / 2 + indent); + cv::Mat warp_mat = cv::getAffineTransform(srcTri, dstTri); + + double* ptr_m = reinterpret_cast(warp_mat.data); + double a = ptr_m[0]; + double b = ptr_m[1]; + double c = ptr_m[2]; + double d = ptr_m[3]; + double e = ptr_m[4]; + double f = ptr_m[5]; + + int x, y; + for (std::vector& sub : contours) + for (cv::Point& p : sub) + { + x = p.x; + y = p.y; + p.x = static_cast(a * x + b * y + c); + p.y = static_cast(d * x + e * y + f); + } + + contours.push_back(std::vector()); + contours[contours.size() - 1].push_back(cv::Point(-1, dstROI.rows - 1)); + contours[contours.size() - 1].push_back(cv::Point(-1, -1)); + contours[contours.size() - 1].push_back(cv::Point(dstROI.cols, -1)); + contours[contours.size() - 1].push_back(cv::Point(dstROI.cols, dst.rows)); + hg::fillPolys(dstROI, contours, blankColor); + } +} diff --git a/app/modules/imgproc/ImageProcess/ImageApplyAutoCrop.h b/app/modules/imgproc/ImageProcess/ImageApplyAutoCrop.h new file mode 100644 index 0000000..020ecfe --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyAutoCrop.h @@ -0,0 +1,125 @@ +/* + * ==================================================== + + * 功能:自动裁剪、纠偏、除黑底 + * 作者:刘丁绿 + * 生成时间_020/4/21 + * 最近修改时间:2020/4/21 v1.0 + 2020/7/22 v1.1 增加获取图像有效区域轮廓的接口maxContour(用于配合一体机的“跳过空白页”算法,PC端暂时无需使用_ + 2020/10/16 v1.2 修复自动裁剪尺寸精度丢失的BUG;提高除黑底缩进精度 + 2020/10/28 v1.2.1 修复凹凸多边形填充背景的逻辑BUG + 2020/10/28 v1.2.2 修复图像处理必定会缩小尺寸的BUG + 2020/10/29 v1.2.3 避免无谓的纠偏(0°纠偏_ + 2020/11/30 v1.3.0 增加功能,可识别文稿颜色进行填充黑底 + 2021/06/18 v1.3.1 调整默认noise + 2021/07/01 v1.3.2 修复 无裁切情况下,自适应颜色除黑底不生效的BUG + 2021/07/08 v1.3.3 完善流程。当无法定位内容时,且为固定幅面裁切,则返回按照固定幅面进行裁切的结果 + 2021/07/08 v1.3.4 调整参数,让消除背景噪声不对纵向像素造成影响 + 2021/07/09 v1.3.5 增加normalCrop机制,当m_isCrop m_isDesaskew m_isFillBlank均为false时可选用,实现传统裁切 + 2021/07/13 v1.3.6 调整normalCrop逻辑,当normalCrop为true时,m_isCrop m_isDesaskew m_isFillBlank失效 + 2021/07/19 v1.3.7 调整仿射变换模式为INTER_LINEAR + 2021/07/22 v1.3.8 修复第二次寻边,找不到外界轮廓会导致崩溃的BUG + 2021/08/02 v1.3.9 精细化除黑底算法,可以应对只有条纹内容的黑色图像 + 2021/10/08 v1.3.10 优化算法,用腐蚀代替绘制实现缩进,提高整体算法效率 + 2021/10/19 v1.3.11 解决一些极端情况,例如纸张自然0角度,纸张定格在图像顶部的处理 + 2021/10/19 v1.3.12 微调裁切纠偏像素精度 + 2022/04/24 v1.4 重构算法,增加除色散功能 + 2022/05/03 v1.4.1 完善逻辑 + 2022/06/09 v1.4.2 修复获取文稿底色时,threshold值,设为固定值0.5 + * 版本号:v1.4.2 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_AUTO_CROP_H +#define IMAGE_APPLY_AUTO_CROP_H + +#include "ImageApply.h" + +class CImageApplyAutoCrop : public CImageApply +{ +public: + CImageApplyAutoCrop(); + + /* + * isCrop [in]:自动幅面裁剪使能,true自动裁剪,false为固定裁剿 + * isDesaskew [in]:自动纠偏使能,true自动纠偏,false为不纠偏 + * isFillBlank [in]:黑底填充使能,true为填充,false为不填充 + * fixedSize [in]:固定幅面尺寸,当isCrop为false时生效,结果尺寸按fixedSize大小输出,单位像紿 + * isConvex [in]:黑底填充时的填充方式,true为凸多边形填充,false为凹多边形填充,默认true + * isFillColor [in]:黑底填充时采用自适应色彩填充,false为白色填充,true为自适应文稿底色填充,默认false + * threshold [in]:二值化阈值,取值范囿0, 255),默访0 + * noise [in]:除噪像素,能够消除noise宽度的背景竖条纹干扰,默访 + * indent [in]:轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进indent像素,默访 + * normalCrop [in]:为true时,m_isCrop m_isDesaskew m_isFillBlank失效,固定裁切采用最传统的裁切方式,默认false + * dispersion [in]:为true时,除色散;false时不除色散。默认为true + */ + CImageApplyAutoCrop(bool isCrop, bool isDesaskew, bool isFillBlank, const cv::Size& fixedSize, bool isConvex = true, + bool isFillColor = false, double threshold = 40, int noise = 8, int indent = 5, bool normalCrop = false, bool dispersion = true); + + virtual ~CImageApplyAutoCrop(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + bool isAutoCrop() { return m_isCrop; } + + bool isFillBlank() { return m_isFillBlank; } + + bool isDesaskew() { return m_isDesaskew; } + + bool isConvexHull() { return m_isConvexHull; } + + cv::RotatedRect getROI() { return m_rect; } + + double threshold() { return m_threshold; } + + int noise() { return m_noise; } + + int indent() { return m_indent; } + + cv::Size fixedSize() { return m_fixedSize; } + + const std::vector& maxContour() { return m_maxContour; } + + void setAutoCrop(bool enabled) { m_isCrop = enabled; } + + void setFillBlank(bool enabled) { m_isFillBlank = enabled; } + + void setDesaskew(bool enabled) { m_isDesaskew = enabled; } + + void setConvexHull(bool convex) { m_isConvexHull = convex; } + + void setThreshold(double value) { m_threshold = value; } + + void setNoise(int value) { m_noise = value; } + + void setIndent(int value) { m_indent = value; } + + void setFixedSize(cv::Size size) { m_fixedSize = size; } + + void setDispersion(bool enable) { m_isDispersion = enable; } + +private: + bool m_isCrop; + bool m_isDesaskew; + bool m_isFillBlank; + bool m_isConvexHull; + bool m_isFillColor; + bool m_isDispersion; + + double m_threshold; + int m_noise; + int m_indent; + bool m_normalCrop; //为true且m_isCrop m_isDesaskew m_isFillBlank均为false时生效,固定裁切采用最传统的裁切方弿 + cv::Size m_fixedSize; + cv::RotatedRect m_rect; + std::vector m_rects; + std::vector m_maxContour; +}; + + +void autoCrop_desaskew_fillBlank(const cv::Mat& src, cv::Mat& dst, bool isAutoCrop, bool isDesaskew, bool isFillBlank, int dWidth, int dHeight, + bool isConvex = true, bool isColorBlank = false, double threshold = 40, int noise = 8, int indent = 5, bool isNormalCrop = false, bool dispersion = true); +#endif // !IMAGE_APPLY_AUTO_CROP_H diff --git a/app/modules/imgproc/ImageProcess/ImageApplyBWBinaray.cpp b/app/modules/imgproc/ImageProcess/ImageApplyBWBinaray.cpp new file mode 100644 index 0000000..f06818e --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyBWBinaray.cpp @@ -0,0 +1,167 @@ +#include "ImageApplyBWBinaray.h" + +CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, int blockSize, int constant) + : m_threshold(threshold) + , m_type(type) + , m_blockSize(blockSize) + , m_constant(constant) + , m_table(new uchar[256]) +{ + memset(m_table, 255, 256); + memset(m_table, 0, static_cast(m_threshold)); +} + +CImageApplyBWBinaray::CImageApplyBWBinaray() + : m_threshold(120) + , m_type(ThresholdType::THRESH_BINARY) + , m_blockSize(51) + , m_constant(41) + , m_table(new uchar[256]) +{ + memset(m_table, 255, 256); + memset(m_table, 0, static_cast(m_threshold)); +} + +CImageApplyBWBinaray::~CImageApplyBWBinaray(void) +{ + delete[] m_table; +} + +#define THRESHOLD_LOW 30 +#define THRESHOLD_UP 245 +void CImageApplyBWBinaray::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()) return; + + if (pDib.channels() == 3) + cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); + + cv::Mat integ; + int blockSize = m_blockSize;//邻域尺寸 + int threshold = m_constant; + int low = THRESHOLD_LOW; + int up = THRESHOLD_UP; + int halfSize = blockSize / 2; + int square_blockSize = blockSize * blockSize; + switch (m_type) + { + case ThresholdType::THRESH_BINARY: + cv::integral(pDib, integ, CV_32S); + + for (int j = halfSize; j < integ.rows - halfSize - 1; j++) + { + uchar* data = pDib.ptr(j); + int* idata1 = integ.ptr(j - halfSize); + int* idata2 = integ.ptr(j + halfSize + 1); + for (int i = halfSize; i < integ.cols - halfSize - 1; i++) + { + if (data[i] < low) + data[i] = 0; + else if (data[i] > up) + data[i] = 255; + else + data[i] = data[i] < ((idata2[i + halfSize + 1] - idata2[i - halfSize] - idata1[i + halfSize + 1] + idata1[i - halfSize]) / square_blockSize - threshold) ? 0 : 255; + } + } + + cv::threshold(pDib(cv::Rect(0, 0, halfSize, pDib.rows)), pDib(cv::Rect(0, 0, halfSize, pDib.rows)), m_threshold, 255, cv::THRESH_BINARY); + cv::threshold(pDib(cv::Rect(pDib.cols - halfSize, 0, halfSize, pDib.rows)), pDib(cv::Rect(pDib.cols - halfSize, 0, halfSize, pDib.rows)), m_threshold, 255, cv::THRESH_BINARY); + cv::threshold(pDib(cv::Rect(0, 0, pDib.cols, halfSize)), pDib(cv::Rect(0, 0, pDib.cols, halfSize)), m_threshold, 255, cv::THRESH_BINARY); + cv::threshold(pDib(cv::Rect(0, pDib.rows - halfSize, pDib.cols, halfSize)), pDib(cv::Rect(0, pDib.rows - halfSize, pDib.cols, halfSize)), m_threshold, 255, cv::THRESH_BINARY); + break; + case ThresholdType::THRESH_OTSU: + cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_OTSU); + break; + case ThresholdType::ADAPTIVE_GAUSSIAN: + cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, m_blockSize, m_constant); + break; + case ThresholdType::ADAPTIVE_MEAN: + cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, m_blockSize, m_constant); + break; + case ThresholdType::ERROR_DIFFUSION: + errorDiffuse(pDib); + break; + default: + break; + } + +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplyBWBinaray apply"); +#endif // LOG +} + +void CImageApplyBWBinaray::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyBWBinaray::errorDiffuse(cv::Mat& image) +{ + if (image.rows < 3 || image.cols < 3) + { + cv::threshold(image, image, m_threshold, 255, CV_THRESH_BINARY); + return; + } + + cv::Mat dst; + image.convertTo(dst, CV_16S); + + size_t rows = static_cast(image.rows) - 1; + size_t cols = static_cast(image.cols) - 1; + + short** pixels_dst = new short* [static_cast(image.rows)]; + for (int i = 0; i < image.rows; i++) + pixels_dst[i] = reinterpret_cast(dst.data + i * static_cast(dst.step)); + + short error; + for (size_t y = 0; y < rows; y++) + for (size_t x = 1; x < cols; x++) + { + short dstPix = pixels_dst[y][x]; + if (dstPix >= m_threshold) + { + pixels_dst[y][x] = 255; + error = dstPix - 255; + } + else + { + pixels_dst[y][x] = 0; + error = dstPix; + } + + pixels_dst[y][x + 1] += error * 1 / 16; + pixels_dst[y + 1][x - 1] += error * 1 / 16; + pixels_dst[y + 1][x] += error * 1 / 16; + pixels_dst[y + 1][x + 1] += error * 1 / 16; + } + image.release(); + dst.convertTo(image, CV_8U); + + rows++; + uchar* ptr = image.data; + size_t step = image.step; + size_t offset; + for (size_t y = 0; y < rows; y++) + { + offset = y * step; + ptr[offset] = m_table[ptr[offset]]; + offset += cols; + ptr[offset] = m_table[ptr[offset]]; + } + + cols++; + ptr = image.data + step * (rows - 1); + for (size_t x = 0; x < cols; x++) + ptr[x] = m_table[ptr[x]]; + + delete[] pixels_dst; +} diff --git a/app/modules/imgproc/ImageProcess/ImageApplyBWBinaray.h b/app/modules/imgproc/ImageProcess/ImageApplyBWBinaray.h new file mode 100644 index 0000000..4eb207c --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyBWBinaray.h @@ -0,0 +1,87 @@ +/* + * ==================================================== + + * 功能:二值化处理 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/5/28 v1.1 修改传统二值化算法,改用自定义局部自适应阈值算法 + 2020/5/29 v1.2 在传统二值化之前添加增强锐化效果,二值化之后增加除噪效果 + 2020/6/19 v1.3 编写自定义自适应阈值二值化;取消锐化处理;保留除噪效果 + 2020/12/21 v1.3.1 调整自适应阈值上下限 + 2020/12/21 v1.3.2 调整blockSize,从原来的51调整到25 + 2022/05/25 v1.3.3 调整blockSize和constant,对THRESH_BINARY同样有效 + * 版本号:v1.3.3 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_BW_BINARAY_H +#define IMAGE_APPLY_BW_BINARAY_H + +#include "ImageApply.h" + +class CImageApplyBWBinaray:public CImageApply +{ +public: + + enum class ThresholdType + { + THRESH_BINARY = 0, //传统二值化 + THRESH_OTSU, //大津阈值 + + ADAPTIVE_GAUSSIAN, //高斯局部自适应阈值 + ADAPTIVE_MEAN, //均值局部自适应阈值 + + ERROR_DIFFUSION //错误扩散 + }; + + /* + * type [in]:二值化模式 + * threshold [in]:阈值,当选择THRESH_OTSU时无效 + * blockSize [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效,表示局部观察块的宽度 + * constant [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效,与blockSize形成比例关系,作为局部筛选阈值 + */ + CImageApplyBWBinaray(ThresholdType type, int threshold = 120, int blockSize = 51, int constant = 41); + + CImageApplyBWBinaray(); + + virtual ~CImageApplyBWBinaray(void); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + double getThreshold() { return m_threshold; } + + ThresholdType getThresholdType() { return m_type; } + + int getBlockSize() { return m_blockSize; } + + double getConstant() { return m_constant; } + + void setThreshold(double value) { m_threshold = value; } + + void setThresholdType(ThresholdType type) { m_type = type; } + + void setBlockSize(int value) { m_blockSize = value; } + + void setConstant(double value) { m_constant = value; } + +private: + + void errorDiffuse(cv::Mat& image); + +private: + double m_threshold; + + ThresholdType m_type; + + int m_blockSize; + + double m_constant; + + uchar* m_table; +}; + +#endif //!IMAGE_APPLY_BW_BINARAY_H + diff --git a/app/modules/imgproc/ImageProcess/ImageApplyChannel.cpp b/app/modules/imgproc/ImageProcess/ImageApplyChannel.cpp new file mode 100644 index 0000000..e1aac59 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyChannel.cpp @@ -0,0 +1,127 @@ +#include "ImageApplyChannel.h" +#include "ImageApplyAdjustColors.h" + +CImageApplyChannel::CImageApplyChannel() + : m_channel(Invalid) + , colors(new CImageApplyAdjustColors(0, 30, 1.0)) +{ +} + +CImageApplyChannel::CImageApplyChannel(Channel channel) + : m_channel(channel) + , colors(new CImageApplyAdjustColors(0, 30, 1.0)) +{ +} + +CImageApplyChannel::~CImageApplyChannel() +{ + if (colors != nullptr) delete colors; +} + +void CImageApplyChannel::apply(cv::Mat& pDib, int side) +{ + (void)side; + if (pDib.empty()) return; + + cv::Mat dst(pDib.rows, pDib.cols, CV_8UC1); + switch (m_channel) + { + case Red: + cv::extractChannel(pDib, dst, 2); + colors->apply(pDib, side); + break; + case Green: + cv::extractChannel(pDib, dst, 1); + break; + case Blue: + cv::extractChannel(pDib, dst, 0); + break; + case All: + colourless(pDib, dst, 80); + break; + case Except_Red: + except_channel(pDib, dst, 2); + break; + case Except_Green: + except_channel(pDib, dst, 1); + break; + case Except_Blue: + except_channel(pDib, dst, 0); + break; + default: + break; + } + pDib.release(); + pDib = dst; + +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplyChannel apply"); +#endif // LOG +} + +void CImageApplyChannel::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyChannel::except_channel(const cv::Mat& src, cv::Mat& dst, int channel) +{ + cv::Mat mv[3]; + cv::split(src, mv); + cv::Mat mask, mask1, mask2; + switch (channel) + { + case 0: + mask1 = mv[0] - mv[1]; + mask2 = mv[0] - mv[2]; + break; + case 1: + mask1 = mv[1] - mv[0]; + mask2 = mv[1] - mv[2]; + break; + case 2: + mask1 = mv[2] - mv[1]; + mask2 = mv[2] - mv[0]; + break; + default: + break; + } + cv::min(mask1, mask2, mask); + + cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY); + dst -= mask; +} + +void CImageApplyChannel::colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold) +{ + if (src.channels() != 3) + { + dst = src; + return; + } + + cv::Mat hsv; + cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV_FULL); + cv::Mat mv_hsv[3]; + cv::split(hsv, mv_hsv); + size_t total = mv_hsv[1].total(); + uchar* ptr_s = mv_hsv[1].data; + uchar* ptr_v = mv_hsv[2].data; + for (size_t i = 0; i < total; i++) + if (ptr_s[i] > threshold) + { + ptr_s[i] = 0; + ptr_v[i] = 255; + } + cv::merge(mv_hsv, 3, hsv); + cv::cvtColor(hsv, hsv, cv::COLOR_HSV2BGR_FULL); + cv::cvtColor(hsv, dst, cv::COLOR_BGR2GRAY); +} diff --git a/app/modules/imgproc/ImageProcess/ImageApplyChannel.h b/app/modules/imgproc/ImageProcess/ImageApplyChannel.h new file mode 100644 index 0000000..afd7e78 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyChannel.h @@ -0,0 +1,65 @@ +/* + * ==================================================== + + * 功能:通道提取,又名除色。可提取BGR图像中的单个通道、两种通道的混合以及去除彩色像素的图像,目标图像均为灰度图 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:v1.0 2020/4/21 + v1.1 2020/6/11 在除红时,增加对比度,提高除色效果。 + v1.2 2020/7/21 修正之前增强红绿蓝效果的色彩配比。 + v1.3 2021/5/24 替换红色增强算法方案。 + * 版本号:v1.3 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_CHANNEL_H +#define IMAGE_APPLY_CHANNEL_H + +#include "ImageApply.h" + +class CImageApplyAdjustColors; +class CImageApplyChannel : public CImageApply +{ +public: + + typedef enum channel + { + Red, //红色通道 + Green, //绿色通道 + Blue, //蓝色通道 + All, //去除所有HSV色彩结构中,S大于80的色彩 + Invalid, //无效 + Except_Red, //绿蓝色通道混合 + Except_Green, //红蓝色通道混合 + Except_Blue //红绿色通道混合 + }Channel; + +public: + + CImageApplyChannel(); + + /* + * channel [in]:通道模式 + * */ + CImageApplyChannel(Channel channel); + + virtual ~CImageApplyChannel(void); + + virtual void apply(cv::Mat& pDib,int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + + void except_channel(const cv::Mat& src, cv::Mat& dst, int channel); + + void colourless(const cv::Mat& src, cv::Mat& dst, uchar threshold = 80); + +private: + + Channel m_channel; + CImageApplyAdjustColors* colors; +}; + +#endif // !IMAGE_APPLY_CHANNEL_H diff --git a/app/modules/imgproc/ImageProcess/ImageApplyColorRecognition.cpp b/app/modules/imgproc/ImageProcess/ImageApplyColorRecognition.cpp new file mode 100644 index 0000000..ef74b01 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyColorRecognition.cpp @@ -0,0 +1,156 @@ +#include "ImageApplyColorRecognition.h" +#include "ImageApplyBWBinaray.h" +#include "ImageApplyAdjustColors.h" + +static CImageApplyBWBinaray m_bw; +static CImageApplyAdjustColors m_ac(0, 50, 1.0f); + +/// +/// 检测图像是否是彩色。当前逻辑仅针对红色像素进行判断,即存在红色像素则为彩色,否则为非彩色 +/// +/// 待测图像 +/// true为彩色,false为非彩色 +bool isColor(const cv::Mat& image) +{ + if (image.channels() != 3) return false; + + cv::Mat pDib_resize; + cv::resize(image, pDib_resize, cv::Size(image.cols / 4, image.rows / 4), 0, 0, cv::INTER_NEAREST); + + cv::Mat hsv; + cv::cvtColor(pDib_resize, hsv, cv::COLOR_BGR2HSV_FULL); + std::vector hsv_channels; + cv::split(hsv, hsv_channels); + + cv::Mat range_s1, range_s2; + cv::inRange(hsv_channels[1], 220, 255, range_s1); //饱和度在[220, 255]的像素 + cv::inRange(hsv_channels[1], 50, 220, range_s2); //饱和度在[50, 220]的像素 +#if 0 + cv::imwrite("range_s1.bmp", range_s1); + cv::imwrite("range_s2.bmp", range_s2); +#endif + double sum = cv::sum(range_s1)[0] / 255; + double total = range_s1.total(); + + // if (sum / total > 0.0001) + if (sum / total > 0.001) + return true; + sum += cv::sum(range_s2)[0] / 255; + // if (sum / total > 0.001) + if (sum / total > 0.03) + return true; + return false; +} + +bool isGray(const cv::Mat& image) +{ + //if (image.channels() == 3) return true; + + //cv::Mat image_clone; + //cv::resize(image, image_clone, cv::Size(), 0.25, 0.25); + //int channels[] = { 0 }; + //int histsize[] = { 256 }; + //float range[] = { 0, 256 }; + //const float* histRanges[] = { range }; + //cv::Mat hist; + //cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, histsize, histRanges, true, false); + //float pixels[256] = { 0 }; + //for (size_t i = 0; i < 256; i++) + // pixels[i] = hist.at(i, 0); + + + //float sum = 0; + //for (size_t i = 0; i < 40; i++) + //{ + + //} + //float pixel_count0 = hist.at(0, 0); + //float pixel_count255 = hist.at(255, 0); + //float total = image_clone.total(); + + //return ((pixel_count0 + pixel_count255) / total) > 0.95; + return false; +} + +CImageApplyColorRecognition::CImageApplyColorRecognition(ColorRecognitionMode mode) + : m_mode(mode) +{ +} + +CImageApplyColorRecognition::~CImageApplyColorRecognition(void) +{ +} + +void CImageApplyColorRecognition::apply(cv::Mat& pDib, int side) +{ + if (pDib.channels() != 3) + { + m_result = Gray; + return; + } + m_result = isColor(pDib) ? Color : Gray; + //if (m_result == Gray && pDib.channels() == 3) + // cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); + + //先判断是否需要判断是彩色 + //if (m_mode == AllColor || m_mode == Color_Gray || m_mode == Color_Mono) + //{ + // //如果是彩色,直接退出 + // if (isColor(pDib)) + // { + // m_result = Color; + // return; + // } + //} + + //if (pDib.channels() == 3) + // cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); + + //if (m_mode == Color_Gray) + //{ + // m_result = Gray; + // return; + //} + + //if (m_mode == Color_Mono) + //{ + // m_bw.apply(pDib, side); + // m_result = Mono; + // return; + //} + + //if (isGray(pDib)) + // m_result = Gray; + //else + //{ + // m_bw.apply(pDib, side); + // m_result = Mono; + //} +} + +void CImageApplyColorRecognition::apply(std::vector& mats, bool isTwoSide) +{ + m_results.clear(); + if (mats.empty()) return; + + if (!mats[0].empty()) + apply(mats[0], 0); + + m_results.push_back(m_result); + + if (isTwoSide && mats.size() > 1) + if (!mats[1].empty()) + apply(mats[1], 1); + + m_results.push_back(m_result); +} + +CImageApplyColorRecognition::ColorType CImageApplyColorRecognition::getResult() +{ + return m_result; +} + +std::vector CImageApplyColorRecognition::getResults() +{ + return m_results; +} diff --git a/app/modules/imgproc/ImageProcess/ImageApplyColorRecognition.h b/app/modules/imgproc/ImageProcess/ImageApplyColorRecognition.h new file mode 100644 index 0000000..408355c --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyColorRecognition.h @@ -0,0 +1,68 @@ +/* + * ==================================================== + + * 功能:色彩识别,将识别会“灰度”的24位图转化为256色8位图, 把识别为“黑白”图转化为二值化的8位图 + * 作者:刘丁维 + * 生成时间:2020/7/17 + * 最近修改时间:2021/04/19 + * 版本号:v1.0 2020/7/17 + * v1.1 2020/12/15 调整策略,仅判断红色像素,存在红色像素为彩色,否则为灰度;删除输出结果,直接转换图像。 + * v1.2 2020/12/16 增加颜色限制模式(输出结果只可能两种),增加结果访问接口 + * v1.3 2021/04/19 修改识别策略,能够识别占比1‰的彩色图像。只区分彩色和灰度图。 + * v1.4 2021/06/18 调整二级色彩区间,从原来的[90, 200]调整为[50, 200]。 + * ==================================================== + */ + +#ifndef IMAGE_APPLY_COLOR_RECOGNITION_H +#define IMAGE_APPLY_COLOR_RECOGNITION_H + +#include "ImageApply.h" + +class CImageApplyColorRecognition : public CImageApply +{ +public: + + //色彩识别模式 + enum ColorRecognitionMode + { + AllColor, //全色模式 识别结果可能会是彩色、灰度、黑白 + Color_Gray, //彩色灰度模式 识别结果只会是彩色或者灰度 + Color_Mono, //彩色黑白模式 识别结果只会是彩色或者黑白 + Gray_Mono //灰度黑白模式 识别结果只会是灰度或者黑白 + }; + + //色彩类型 + enum ColorType + { + Color, //彩色 + Gray, //灰度 + Mono //黑白 + }; +public: + CImageApplyColorRecognition(ColorRecognitionMode mode = AllColor); + + virtual ~CImageApplyColorRecognition(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + /// + /// 获取图片色彩类型。配合void apply(cv::Mat&, int)接口使用 + /// + /// 色彩类型 + ColorType getResult(); + + /// + /// 获取图片色彩类型。配合void apply(std::vector&, int)接口使用 + /// + /// 色彩类型数组 + std::vector getResults(); + +private: + ColorType m_result; + std::vector m_results; + ColorRecognitionMode m_mode; +}; + +#endif // !IMAGE_APPLY_CONCATENATION_H diff --git a/app/modules/imgproc/ImageProcess/ImageApplyDiscardBlank.cpp b/app/modules/imgproc/ImageProcess/ImageApplyDiscardBlank.cpp new file mode 100644 index 0000000..8134f36 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyDiscardBlank.cpp @@ -0,0 +1,114 @@ +#include "ImageApplyDiscardBlank.h" +#include "ImageProcess_Public.h" + +CImageApplyDiscardBlank::CImageApplyDiscardBlank(double threshold, int edge, double devTh, double meanTh) + : m_threshold(threshold) + , m_edge(edge) + , m_devTh(devTh) + , m_meanTh(meanTh) +{ +} + +CImageApplyDiscardBlank::~CImageApplyDiscardBlank(void) +{ +} + +void CImageApplyDiscardBlank::apply(cv::Mat& pDib, int side) +{ + if (apply(pDib, m_threshold, m_edge, m_devTh)) + pDib.release(); +} + +void CImageApplyDiscardBlank::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +bool scalar_LE(const cv::Scalar& val1, const cv::Scalar& val2) +{ + for (int i = 0; i < 3; i++) + if (val1[i] > val2[i]) + return false; + return true; +} + +bool maxMinCompare(const cv::Mat& img, const cv::Mat& mask, double devTh, double meanTh) +{ + double min, max; + cv::minMaxLoc(img, &min, &max, 0, 0, mask); + if (cv::mean(img, mask)[0] < meanTh) + return false; + return (max - min) < devTh; +} + +bool CImageApplyDiscardBlank::apply(const cv::Mat& pDib, double threshold, int edge, int blockSize, double devTh, double meanTh) +{ + if (pDib.empty()) + return true; + + cv::Mat img_resize; + cv::resize(pDib, img_resize, cv::Size(), 0.2, 0.2); + + cv::Mat threshold_img; + if (img_resize.channels() == 3) + cv::cvtColor(img_resize, threshold_img, cv::COLOR_BGR2GRAY); + cv::threshold(img_resize.channels() == 3 ? threshold_img : img_resize, threshold_img, threshold, 255, CV_THRESH_BINARY); + + std::vector> contours; + std::vector h1; + hg::findContours(threshold_img, contours, h1, cv::RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); + + std::vector contour; + for (const std::vector& sub : contours) + for (const cv::Point& p : sub) + contour.push_back(p); + + cv::RotatedRect rect = hg::getBoundingRect(contour); + rect.size = cv::Size2f(rect.size.width - edge / 2.5, rect.size.height - edge / 2.5); + cv::Point2f box[4]; + rect.points(box); + contour.clear(); + contours.clear(); + + for (size_t i = 0; i < 4; i++) + contour.push_back(box[i]); + contours.push_back(contour); + cv::Mat mask = cv::Mat::zeros(img_resize.size(), CV_8UC1); + hg::fillPolys(mask, contours, cv::Scalar::all(255)); + cv::blur(img_resize, img_resize, cv::Size(3, 3)); + + bool b = true; + if (img_resize.channels() == 3) + { + cv::Mat bgr[3]; + cv::split(img_resize, bgr); + for (size_t i = 0; i < 3; i++) + { + b &= maxMinCompare(bgr[i], mask, devTh, meanTh); + if (!b) break; + } + } + else + b &= maxMinCompare(img_resize, mask, devTh, meanTh); + /* + if (b) + { + cv::imwrite("空白页/img1/" + std::to_string(index) + ".bmp", img_resize); + cv::imwrite("空白页/mask1/" + std::to_string(index) + ".bmp", mask); + } + else + { + cv::imwrite("空白页/img2/" + std::to_string(index) + ".bmp", img_resize); + cv::imwrite("空白页/mask2/" + std::to_string(index) + ".bmp", mask); + }*/ + + return b; +} diff --git a/app/modules/imgproc/ImageProcess/ImageApplyDiscardBlank.h b/app/modules/imgproc/ImageProcess/ImageApplyDiscardBlank.h new file mode 100644 index 0000000..d49f628 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyDiscardBlank.h @@ -0,0 +1,48 @@ +/* + * ==================================================== + + * 功能:空白页识别。 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 v1.0 + 2020/8/12 v1.1 开放setIntensity和setMinArea;取消isNormal标识位;扩大setIntensity的设置范围,从[2, 20]扩大到[1, 100] + 2020/8/25 v1.1.1 纸张检测缩进,从100像素调整到20像素 + 2020/10/16 v1.2 添加新接口,能够高效便捷判断图片是否为空白页 + 2020/10/19 v1.2.1 修复静态空白页判断识别误判的BUG + 2021/04/13 v1.3.0 增加标准/票据标识位 + 2021/08/12 v1.3.1 添加防止不同opencv版本导致计算结果存在差异的代码。 + 2021/12/14 v1.3.2 重构算法。 + 2021/12/15 v1.3.3 微调参数。 + 2021/12/17 v1.3.4 增加背景色接口,实现对纯色纸张的空白页判定 + * 版本号:v1.3.4 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_DISCARD_BLANK_H +#define IMAGE_APPLY_DISCARD_BLANK_H + +#include "ImageApply.h" + +class CImageApplyDiscardBlank : public CImageApply +{ +public: + + CImageApplyDiscardBlank(double threshold = 40, int edge = 150, double devTh = 50, double meanTh = 200); + + virtual ~CImageApplyDiscardBlank(void); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + static bool apply(const cv::Mat& pDib, double threshold = 40, int edge = 150, int blockSize = 10, double devTh = 50, double meanTh = 200); + +private: + double m_threshold; + int m_edge; + double m_devTh; + double m_meanTh; +}; + +#endif // !IMAGE_APPLY_DISCARD_BLANK_H \ No newline at end of file diff --git a/app/modules/imgproc/ImageProcess/ImageApplyDispersion.cpp b/app/modules/imgproc/ImageProcess/ImageApplyDispersion.cpp new file mode 100644 index 0000000..843db70 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyDispersion.cpp @@ -0,0 +1,44 @@ +#include "ImageApplyDispersion.h" + +CImageApplyDispersion::CImageApplyDispersion() + : CImageApply() + , m_kernal_b(3, 1, CV_32FC1) + , m_kernal_g(3, 1, CV_32FC1) + , m_kernal_r(3, 1, CV_32FC1) +{ + m_kernal_b.at(0, 0) = 0.15f; + m_kernal_b.at(1, 0) = 1.15f; + m_kernal_b.at(2, 0) = -0.3f; + + m_kernal_g.at(0, 0) = 0.806f; + m_kernal_g.at(1, 0) = 0.484f; + m_kernal_g.at(2, 0) = -0.3f; + + m_kernal_r.at(0, 0) = 0.484f; + m_kernal_r.at(1, 0) = 0.806f; + m_kernal_r.at(2, 0) = -0.3f; +} + +CImageApplyDispersion::~CImageApplyDispersion() +{ +} + +void CImageApplyDispersion::apply(cv::Mat& pDib, int side) +{ + (void)side; + + if (pDib.channels() != 3) return; + + cv::Mat bgr[3]; + cv::split(pDib, bgr); + + cv::filter2D(bgr[0], bgr[0], bgr[0].depth(), m_kernal_b); + cv::filter2D(bgr[1], bgr[1], bgr[1].depth(), m_kernal_g); + cv::filter2D(bgr[2], bgr[2], bgr[2].depth(), m_kernal_r); + + cv::merge(bgr, 3, pDib); +} + +void CImageApplyDispersion::apply(std::vector& mats, bool isTwoSide) +{ +} diff --git a/app/modules/imgproc/ImageProcess/ImageApplyDispersion.h b/app/modules/imgproc/ImageProcess/ImageApplyDispersion.h new file mode 100644 index 0000000..9273f74 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyDispersion.h @@ -0,0 +1,35 @@ +/* + * ==================================================== + + * 功能:消除色散 + * 作者:刘丁维 + * 生成时间:2021/09/24 + * 最近修改时间:2021/11/12 v1.1.0 重构算法 + * 2022/04/21 v1.2.0 重构算法 + * 版本号:v1.2.0 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_DISPERSION_COLOR_H +#define IMAGE_APPLY_DISPERSION_COLOR_H + +#include "ImageApply.h" + +class CImageApplyDispersion : public CImageApply +{ +public: + CImageApplyDispersion(); + + virtual ~CImageApplyDispersion(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + cv::Mat m_kernal_b; + cv::Mat m_kernal_g; + cv::Mat m_kernal_r; +}; +#endif diff --git a/app/modules/imgproc/ImageProcess/ImageApplyFadeBackGroundColor.cpp b/app/modules/imgproc/ImageProcess/ImageApplyFadeBackGroundColor.cpp new file mode 100644 index 0000000..a18eef3 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyFadeBackGroundColor.cpp @@ -0,0 +1,150 @@ +#include "ImageApplyFadeBackGroundColor.h" + + +CImageApplyFadeBackGroudColor::CImageApplyFadeBackGroudColor(int threshold, int offset, int range) + : m_threshold(threshold) + , m_offset(offset) + , m_range(range) +{ + memset(m_table1, 255, 768); + memset(m_table1, 0, m_threshold * 3); + + memset(m_table2, 255, 256 * 3); + for (size_t i = 0; i < 256; i++) + m_table2[i] = (uchar)i; +} + +CImageApplyFadeBackGroudColor::~CImageApplyFadeBackGroudColor() +{ +} + +void CImageApplyFadeBackGroudColor::apply(cv::Mat& pDib, int side) +{ + if (pDib.channels() != 3) + return; + +#if 0 + cv::Mat mask; + cv::cvtColor(pDib, mask, cv::COLOR_BGR2GRAY); + cv::threshold(mask, mask, m_threshold, 255, cv::THRESH_BINARY); + //cv::imwrite("mask.jpg", mask); + cv::Mat bgr[3]; + cv::split(pDib, bgr); + + int histSize = 255; + float range[] = { 0, 255 }; + const float* histRange = { range }; + + cv::Mat hist_bgr[3]; + cv::Scalar mean_bgr; + for (size_t i = 0; i < 3; i++) + { + cv::calcHist(&bgr[i], 1, 0, mask, hist_bgr[i], 1, &histSize, &histRange); + double maxVal = 0; + cv::Point maxLoc; + cv::minMaxLoc(hist_bgr[i], NULL, &maxVal, NULL, &maxLoc); + mean_bgr[i] = maxLoc.y; + } + + cv::add(pDib, cv::Scalar::all(255 + m_offset) - mean_bgr, pDib, mask); +#else + fadeBackground(pDib.data, pDib.step, pDib.rows, m_threshold, m_offset, m_range); +#endif +} + +void CImageApplyFadeBackGroudColor::fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range) +{ + int hist_bgr[3][256] = { 0 }; + + int width = bytesPerLine / 3; + unsigned char* mask = new unsigned char[width * height]; + unsigned char* ptr_data = data; + unsigned char* ptr_mask = mask; + + //创建掩模mask,并且统计三通道的直方图 + for (int i = 0; i < height; i++) + { + int x = 0; + unsigned char b = 0; + for (int j = 0; j < width; j++) + { + b = m_table1[ptr_data[x] + ptr_data[x + 1] + ptr_data[x + 2]]; + ptr_mask[j] = b; + for (size_t k = 0; k < 3; k++) + hist_bgr[k][ptr_data[x + k] & b]++; + x += 3; + } + ptr_data += bytesPerLine; + ptr_mask += width; + } + + //统计背景色 + int max_vals[3] = { 0 }; + int max_indexes[3] = { 0 }; + + for (size_t i = 1; i < 256; i++) + for (size_t j = 0; j < 3; j++) + if (hist_bgr[j][i] > max_vals[j]) + { + max_vals[j] = hist_bgr[j][i]; + max_indexes[j] = i; + } + + //创建背景色误查值表,在误差±range范围内的颜色被同样视为背景色 + for (size_t i = 0; i < 3; i++) + { + memset(m_table_rgb[i], 0, 256); + int start = cv::max(max_indexes[i] - range, 0); + int end = cv::min(max_indexes[i] + range, 255); + memset(m_table_rgb[i] + start, 255, end - start + 1); + } + + //根据背景色误差查值表,更新掩模,排除背景色以外的内容 + ptr_data = data; + ptr_mask = mask; + for (int i = 0; i < height; i++) + { + int x = 0; + for (int j = 0; j < width; j++) + { + ptr_mask[j] &= m_table_rgb[0][ptr_data[x]] & m_table_rgb[1][ptr_data[x + 1]] & m_table_rgb[2][ptr_data[x + 2]]; + x += 3; + } + ptr_data += bytesPerLine; + ptr_mask += width; + } + + //根据掩模,除背景色 + unsigned char offset_rgb[3]; + for (size_t i = 0; i < 3; i++) + offset_rgb[i] = 255 + offset - max_indexes[i]; + + ptr_data = data; + ptr_mask = mask; + for (int i = 0; i < height; i++) + { + int x = 0; + for (int j = 0; j < width; j++) + { + for (size_t k = 0; k < 3; k++) + ptr_data[x + k] = m_table2[(int)ptr_data[x + k] + (offset_rgb[k] & ptr_mask[j])]; + x += 3; + } + ptr_data += bytesPerLine; + ptr_mask += width; + } + delete[] mask; +} + +void CImageApplyFadeBackGroudColor::apply(std::vector& mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) + if (!var.empty()) + { + apply(var, i); + i++; + } +} + diff --git a/app/modules/imgproc/ImageProcess/ImageApplyFadeBackGroundColor.h b/app/modules/imgproc/ImageProcess/ImageApplyFadeBackGroundColor.h new file mode 100644 index 0000000..f0a50db --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyFadeBackGroundColor.h @@ -0,0 +1,65 @@ +/* + * ==================================================== + + * 功能:消除文稿纸张底色 + * 作者:刘丁维 + * 生成时间:2020/11/30 + * 最近修改时间:2021/04/14 v2.0 改为档位设置 + * 2021/04/14 v2.1 调整方案,与LINUX方案保持一致。 + * 2021/08/03 v2.2 自定义获取饱和度算法,避免不同opencv版本结果存在偏差。 + * 2021/10/12 v2.3 重构算法,去除原来分档设定改为自动识别颜色,并去除底色。 + * 2021/10/23 v3.0 重构算法。避开黑色背景(制作掩模),计算文稿平均底色,并进行增白。 + * 2021/10/26 v3.1 构造函数增加参数,可设置生成掩模时的阈值。 + * 2021/10/28 v3.2 重构算法,改用纯C++代码实现功能,提高处理速度。 + * 2021/10/29 v3.3 优化算法,增加range参数。针对复杂内容的图像,能够有效甄别背景和非背景内容。 + * 2022/03/08 v3.4 修复变量未初始化的BUG。 + * 版本号:v3.4 + + * ==================================================== + */ + + +#ifndef IMAGE_APPLY_FADE_BACKGROUND_COLOR_H +#define IMAGE_APPLY_FADE_BACKGROUND_COLOR_H + +#include "ImageApply.h" + +class CImageApplyAdjustColors; +class CImageApplyFadeBackGroudColor : public CImageApply +{ +public: + /// + /// 构造函数 + /// + /// 在自动识别增白参数的基础上,增加的偏移量。取值范围[-255, 255] + CImageApplyFadeBackGroudColor(int threshold = 100, int offset = 0, int range = 40); + + virtual ~CImageApplyFadeBackGroudColor(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + +private: + + /// + /// 除文稿底色算法,仅支持24位图像 + /// + /// 图像数据头指针 + /// 每行数据大小 + /// 图像高度 + /// 阈值,参考值为100 + /// 文稿底色增亮偏移量,默认为0。值越大,背景越白,反之越暗 + /// 底色误差范围,色彩与识别到的底色误差在[-range, range]范围内,视为底色,否则不会被消除 + void fadeBackground(unsigned char* data, int bytesPerLine, int height, int threshold, int offset, int range); + +private: + int m_threshold; + int m_offset; + int m_range; + uchar m_table1[768]; + uchar m_table2[512]; + uchar m_table_rgb[3][256]; +}; + +#endif // !IMAGE_APPLY_FADE_BACKGROUND_COLOR_H diff --git a/app/modules/imgproc/ImageProcess/ImageApplyFilter.cpp b/app/modules/imgproc/ImageProcess/ImageApplyFilter.cpp new file mode 100644 index 0000000..1f0430e --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyFilter.cpp @@ -0,0 +1,97 @@ +#include "ImageApplyFilter.h" + +CImageApplyFilter::CImageApplyFilter(FilterMode type, int kSize) + : m_type(type) + , m_kernel(kSize) +{ + m_kSize = (m_type == FilterMode::Sharpen || m_type == FilterMode::AverBlur) ? 5 : 9; +} + +CImageApplyFilter::~CImageApplyFilter() +{ +} + +void CImageApplyFilter::apply(cv::Mat& pDib, int side) +{ +#ifdef LOG + FileTools::write_log("imgprc.txt", "enter CImageApplySharpen apply"); +#endif // LOG + + switch (m_type) + { + case FilterMode::Sharpen: + case FilterMode::Sharpen_More: + sharpen(pDib, m_kSize); + break; + case FilterMode::AverBlur: + case FilterMode::AverBlur_More: + averblur(pDib, static_cast(m_kSize)); + break; + case FilterMode::BilateralFilter: + bilateralFilter(pDib, m_kernel); + break; + case FilterMode::GaussianBlur: + gaussianBlur(pDib, m_kernel); + break; + case FilterMode::BrightSharp: + brightSharp(pDib); + break; + } + +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit CImageApplySharpen apply"); +#endif // LOG +} + +void CImageApplyFilter::apply(std::vector& mats, bool isTwoSide) +{ + if (mats.empty()) return; + + if (!mats[0].empty()) + apply(mats[0], 0); + + if (isTwoSide && mats.size() > 1) + if (!mats[1].empty()) + apply(mats[1], 1); +} + +void CImageApplyFilter::averblur(cv::Mat& src, int kSize) +{ + cv::blur(src, src, cv::Size(kSize, kSize)); +} + +void CImageApplyFilter::sharpen(cv::Mat& src, float kSize) +{ + float other = (1.0f - kSize) / 4; + float kernel_data[] = { 0, other, 0, other, kSize, other, 0, other, 0 }; + cv::Mat kernel(3, 3, CV_32FC1, kernel_data); + + cv::filter2D(src, src, src.depth(), kernel); +} + +void CImageApplyFilter::brightSharp(cv::Mat& src) +{ + const float a = -0.49f; + const float b = 3.0f; + float kernel_data[] = + { + 0, a, 0, + a, b, a, + 0, a, 0 + }; + cv::Mat kernel(3, 3, CV_32FC1, kernel_data); + cv::filter2D(src, src, src.depth(), kernel); +} + +void CImageApplyFilter::bilateralFilter(cv::Mat& src, double kernel) +{ + cv::Mat dst; + cv::bilateralFilter(src, dst, static_cast(kernel), kernel * 2, kernel / 2); + src.release(); + src = dst; +} + +void CImageApplyFilter::gaussianBlur(cv::Mat& src, int kSize) +{ + cv::GaussianBlur(src, src, cv::Size(kSize, kSize), 0); +} diff --git a/app/modules/imgproc/ImageProcess/ImageApplyFilter.h b/app/modules/imgproc/ImageProcess/ImageApplyFilter.h new file mode 100644 index 0000000..f11ea93 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyFilter.h @@ -0,0 +1,64 @@ +/* + * ==================================================== + + * 功能:滤镜。目前包括锐化、加强锐化、模糊和加强模糊 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 v1.0 + 2020/7/17 v1.1 增加双边滤波(BilateralFilter)效果,用于实现“背景平滑”功能; + 2020/11/30 v1.2 增加高斯模糊(GaussianBlur) + 2021/07/21 v1.2.1 增加增亮锐化(BrightSharp) + 2021/10/19 v1.2.2 调整增亮锐化参数 + * 版本号:v1.2.2 + + * ==================================================== + */ + + +#ifndef IMAGE_APPLY_FILTER_H +#define IMAGE_APPLY_FILTER_H + +#include "ImageApply.h" + +class CImageApplyFilter : public CImageApply +{ +public: + enum FilterMode + { + None, + Sharpen, //锐化 + Sharpen_More, //进一步锐化 + AverBlur, //模糊 + AverBlur_More, //进一步模糊 + BilateralFilter, //双边滤波--背景平滑,减少复杂背景的色彩数量,利于jpg等压缩比例 + GaussianBlur, + BrightSharp //5 * 5提亮锐化 + }; + + /* + * sharpentype [in]:滤镜模式 + */ + CImageApplyFilter(FilterMode type, int kSize = 30); + + virtual ~CImageApplyFilter(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); +private: + void averblur(cv::Mat& src, int kSize); + + void sharpen(cv::Mat& src, float kSize); + + void brightSharp(cv::Mat& src); + + void bilateralFilter(cv::Mat& src, double kernel); + + void gaussianBlur(cv::Mat& src, int kSize); +private: + int m_type; + float m_kSize; + double m_kernel; +}; + +#endif // !IMAGE_APPLY_SHARPEN_H diff --git a/app/modules/imgproc/ImageProcess/ImageApplyHSVCorrect.cpp b/app/modules/imgproc/ImageProcess/ImageApplyHSVCorrect.cpp new file mode 100644 index 0000000..4fa0505 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyHSVCorrect.cpp @@ -0,0 +1,163 @@ +#include "ImageApplyHSVCorrect.h" +#include + +CImageApplyHSVCorrect::CImageApplyHSVCorrect(CorrectOption mode, bool cvtColor, uint bgr) + : m_table(new uint[256 * 256 * 256]) +{ + initLUT(); + switch (mode) + { + case CImageApplyHSVCorrect::Red_Removal: + set_HSV_value(std::pair(0, 63), std::pair(30, 255), std::pair(120, 255), bgr, cvtColor); + set_HSV_value(std::pair(200, 255), std::pair(30, 255), std::pair(120, 255), bgr, cvtColor); + break; + case CImageApplyHSVCorrect::LowSaturation_Removal: + set_HSV_value(std::pair(0, 255), std::pair(0, 30), std::pair(0, 255), bgr, cvtColor); + break; + default: + break; + } +} + +CImageApplyHSVCorrect::~CImageApplyHSVCorrect() +{ + delete [] m_table; +} + +void CImageApplyHSVCorrect::apply(cv::Mat &pDib, int side) +{ + (void)side; + if (pDib.empty() || pDib.channels() != 3) return; +#if 0 + uchar* src = pDib.data; + cv::Mat z = cv::Mat::zeros(pDib.size(), CV_8UC3); + uchar* dst = z.data; + + int bytesPerLine = pDib.cols * pDib.channels(); + for (size_t i = 0, rows = pDib.rows; i < rows; i++) + { + uchar* ptr = pDib.ptr(i); + for (size_t j = 0, cols = pDib.cols; j < cols; j++) + { + int offset = i * 3; + int index = *reinterpret_cast(ptr + offset) & 0x00ffffff; + uint color = m_table[index]; + *reinterpret_cast(dst + offset) |= color; + } + } + pDib = z; +#else + cv::Mat bgra; + cv::cvtColor(pDib, bgra, cv::COLOR_BGR2BGRA); + + long total = bgra.total(); + uint* ptr = bgra.ptr(); + for (long i = 0; i < total; i++) + ptr[i] = m_table[ptr[i] & 0x00FFFFFF]; + + cv::cvtColor(bgra, pDib, cv::COLOR_BGRA2BGR); +#endif +} + +void CImageApplyHSVCorrect::apply(std::vector &mats, bool isTwoSide) +{ + (void)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; + } +} + +void CImageApplyHSVCorrect::initLUT() +{ +#if 0 + uchar h, s, v; +#endif + for (uint b = 0; b < 256; b++) + for (uint g = 0; g < 256; g++) + for (uint r = 0; r < 256; r++) + { +#if 0 + RGB_2_HSV_full(r, g, b, h, s, v); + + uint index = b | (g << 8) | (r << 16); + if (h < 12 || h > 245) + m_table[index] = index & 0x00ffffff; + else + m_table[index] = (v | (v << 8) | (v << 16)) & 0x00ffffff; +#else + m_table[b | (g << 8) | (r << 16)] = b | (g << 8) | (r << 16); +#endif + } +} + +void CImageApplyHSVCorrect::set_single(const uint src_b, const uint src_g, const uint src_r, + const uint dst_b, const uint dst_g, const uint dst_r) +{ + m_table[src_b | (src_g << 8) | (src_r << 16)] = dst_b | (dst_g << 8) | (dst_r << 16); +} + +void CImageApplyHSVCorrect::set_HSV_value(const std::pair& range_h, + const std::pair& range_s, + const std::pair& range_v, + uint bgr, bool cvtGray) +{ + uchar h, s, v; + for (int b = 0; b < 256; b++) + for (int g = 0; g < 256; g++) + for (int r = 0; r < 256; r++) + { + RGB_2_HSV_full(r, g, b, h, s, v); + if (contained(h, range_h) && contained(s, range_s) && contained(v, range_v)) + { + if (cvtGray) + { + int a = (b + g + r) / 3 * 0x00010101; + m_table[(b | (g << 8) | (r << 16)) & 0x00ffffff] = (b + g + r) / 3 * 0x00010101; + } + else + m_table[(b | (g << 8) | (r << 16)) & 0x00ffffff] = bgr & 0x00ffffff; + } + } +} + +void CImageApplyHSVCorrect::set_table(const uint* table) +{ + memcpy(m_table, table, 256 * 256 * 256 * sizeof(uint)); +} + +bool CImageApplyHSVCorrect::contained(uchar value, const std::pair &range) +{ + return value >= range.first && value <= range.second; +} + +void CImageApplyHSVCorrect::RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v) +{ + int minn = cv::min(r, cv::min(g, b)); + int maxx = cv::max(r, cv::max(g, b)); + v = static_cast(maxx); //V + + int delta = maxx - minn; + float _h; + if (maxx == 0) + { + h = s = v = 0; + return; + } + else + s = static_cast(delta * 255 / maxx); + + if (r == maxx) + _h = static_cast(g - b) / static_cast(delta); + else if (g == maxx) + _h = 2 + static_cast(b - r) / static_cast(delta); + else + _h = 4 + static_cast(r - g) / static_cast(delta); + + float __h = _h * 42.6666666667f; + h = (__h >= 0) ? static_cast(__h) : static_cast(__h + 256); +} diff --git a/app/modules/imgproc/ImageProcess/ImageApplyHSVCorrect.h b/app/modules/imgproc/ImageProcess/ImageApplyHSVCorrect.h new file mode 100644 index 0000000..2c36107 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyHSVCorrect.h @@ -0,0 +1,95 @@ +/* + * ==================================================== + * + * 功能:彩色图像,色彩校正。基于LUT实现,预设BGR查值表(表达所有HVS),对BGR原图进行查值校正。 + * 作者:刘丁维 + * 生成时间:2020/3/21 + * 最近修改时间:v1.0 2020/03/21 + v1.1 2020/06/15 调整除红效果的HSV取值范围 + v1.2 2021/08/02 调整内存指针,适应ROI图像的内存偏移。 + v1.3 2021/08/26 替换答题卡除红Red_Removal实现方案。 + v1.4 2022/04/22 增加功能,支持用像素灰度值填充原来彩色像素;删除默认构造函数;增加校正选项Deafault和LowSaturation_Removal + v1.4.1 2022/04/25 调整数据类型,避免数据访问越界。 + v1.4.2 2022/06/09 修复一个内存大小的错误。 + * 版本号:v1.4.2 + * + * ==================================================== + */ + +#ifndef IMAGE_APPLY_COLOR_CORRECT_H +#define IMAGE_APPLY_COLOR_CORRECT_H + +#include "ImageApply.h" + +class CImageApplyHSVCorrect : public CImageApply +{ +public: + enum CorrectOption + { + Deafault, //默认,无任何除色效果 + LowSaturation_Removal, //除掉低饱和度像素 + Red_Removal //除掉红色。红色定义H:[0, 85]∪[170, 255],S:[10, 255],V:[120,255] + }; +public: + /* + * mode [in]:预设初色模式 + * cvtColor [in]:替代像素使用默认值,还是使用灰度值。true为灰度值,false为默认值 + * bgr:[in] 用uint表示BGR值,B在低位,R在高位。(当cvtGray 为false时生效) + */ + CImageApplyHSVCorrect(CorrectOption mode = CorrectOption::Deafault, bool cvtColor = false, uint bgr = 0x00FFFFFF); + + virtual ~CImageApplyHSVCorrect(); + + virtual void apply(cv::Mat& pDib, int side); + + virtual void apply(std::vector& mats, bool isTwoSide); + + /* + * 函数功能:初始化查值表,按照RGB(R在高位,B在低位)的32位数据进行索引,值与索引一致。 + 表中索引范围[0,0x00FFFFFF]。在构造函数中会默认调用该函数。 + */ + void initLUT(); + + /* + * 函数功能:将查值表指定RGB索引值设置为目标值。 + 索引 = src_b | (src_g << 8) | (src_r << 16) + 值 = dst_b | (dst_g << 8) | (dst_r << 16) + * src_b:[in] 原查值表B通道索引 + * src_g:[in] 原查值表G通道索引 + * src_r:[in] 原查值表R通道索引 + * dst_b:[in] 目标查值表B通道值 + * dst_g:[in] 目标查值表G通道值 + * dst_r:[in] 目标查值表R通道值 + */ + void set_single(const uint src_b, const uint src_g, const uint src_r, + const uint dst_b, const uint dst_g, const uint dst_r); + + /* + * 函数功能:按照HSV色彩空间描述色彩范围,将该范围对应的BGR索引设置为0x00FFFFFF(默认白色) + * range_h:[in] H分量范围,取值范围[0, 255] + * range_s:[in] S分量范围,取值范围[0, 255] + * range_v:[in] V分量范围,取值范围[0, 255] + * bgr:[in] 用uint表示BGR值,B在低位,R在高位。(当cvtGray 为false时生效) + * cvtGray:[in] 为true时,根据RGB值转换为灰度值 + */ + void set_HSV_value(const std::pair& range_h, + const std::pair& range_s, + const std::pair& range_v, + uint bgr = 0x00FFFFFF, bool cvtGray = false); + + /* + * 函数功能:设置外部查值表,表默认长度为 256 * 256 * 256 * sizeof(uint) + * table:[in] 数组指针 + */ + void set_table(const uint* table); + +private: + static bool contained(uchar value, const std::pair& range); + + static void RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v); + +private: + uint* m_table; +}; + +#endif diff --git a/app/modules/imgproc/ImageProcess/ImageApplyOutHole.cpp b/app/modules/imgproc/ImageProcess/ImageApplyOutHole.cpp new file mode 100644 index 0000000..98a3d2d --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyOutHole.cpp @@ -0,0 +1,332 @@ +#include "ImageApplyOutHole.h" +#include "ImageProcess_Public.h" + +#ifdef LOG +#include "Device/filetools.h" +#endif // LOG + +CImageApplyOutHole::CImageApplyOutHole(void) + : CImageApply() + , m_borderSize(600) + , m_edgeScale(0.1f) + , m_threshold(100) +{ +} + +CImageApplyOutHole::CImageApplyOutHole(float borderSize, float edgeScale, double threshold) + : CImageApply() + , m_borderSize(borderSize) + , m_edgeScale(edgeScale) + , m_threshold(threshold) +{ +} + +CImageApplyOutHole::~CImageApplyOutHole(void) +{ +} + +void CImageApplyOutHole::apply(cv::Mat& pDib, int side) +{ + (void)pDib; + (void)side; +} + +void CImageApplyOutHole::apply(std::vector& mats, bool isTwoSide) +{ +#ifdef LOG + FileTools::write_log("imgprc.txt", "enter ImageOutHole apply"); +#endif // LOG + + if (mats.size() < 2) + { +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); +#endif // LOG + return; + } + + if (mats[0].empty() || mats[1].empty()) + { +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); +#endif // LOG + return; + } + + //二值化正反面图像 + cv::Mat front = mats[0]; + cv::Mat back = mats[1]; + cv::Mat front_thre, back_thre; + hg::threshold_Mat(front, front_thre, m_threshold); + hg::threshold_Mat(back, back_thre, m_threshold); + + cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(10, 1)); + cv::morphologyEx(front_thre, front_thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + cv::morphologyEx(back_thre, back_thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + + //反面二值化图像水平翻转 + cv::flip(back_thre, back_thre, 1); //1:Horizontal + + //正反面图像寻边 + std::vector> contours_front, contours_back; + std::vector b1_front, b1_back; + hg::findContours(front_thre.clone(), contours_front, b1_front, cv::RETR_EXTERNAL); + hg::findContours(back_thre.clone(), contours_back, b1_back, cv::RETR_EXTERNAL); + + //提取正反面图像最大轮廓 + std::vector maxContour_front = hg::getMaxContour(contours_front, b1_front); + std::vector maxContour_back = hg::getMaxContour(contours_back, b1_back); + + if (maxContour_front.empty() || maxContour_back.empty()) + return; + + cv::RotatedRect rrect_front = hg::getBoundingRect(maxContour_front); //提取正面最大轮廓的最小外接矩形 + cv::RotatedRect rrect_back = hg::getBoundingRect(maxContour_back); //提取反面最大轮廓的最小外接矩形 + + //如果正反面图像尺寸差异超过20个像素,直接放弃处理 + if (cv::abs(rrect_front.size.width - rrect_back.size.width) > 20 || + cv::abs(rrect_front.size.height - rrect_back.size.height) > 20) + return; + + //提取正反面图像重叠部分区域 + cv::Rect roi_front, roi_back; + cv::RotatedRect mask_rotatedRect; + getRoi(rrect_front, rrect_back, front.size(), back.size(), roi_front, roi_back, mask_rotatedRect); + + cv::Mat roiMat_front(front_thre, roi_front); //在正面二值图像中截取重叠部分 + cv::Mat roiMat_back(back_thre, roi_back); //在反面二值图像中截取重叠部分 + + //正反面二值图像做或运算,真正镂空区域保留0,其他地方填充为255 + cv::Mat mask; + cv::bitwise_or(roiMat_front, roiMat_back, mask); //或运算,正反面二值图像重叠 + + //二值图像重叠图像颜色取反,膨胀,提取轮廓 + cv::bitwise_not(mask, mask); //反色 + + element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(10, 10)); + cv::dilate(mask, mask, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar(255)); //膨胀算法,增大孔洞连通区域面积 + + //为了避免孔洞彻底贯穿纸边,人为绘制纸张轮廓,确保所有孔洞为封闭图形,不会与背景粘连 + cv::polylines(mask, hg::getVertices(mask_rotatedRect), true, cv::Scalar(0), 15); //绘制纸张矩形边缘 + + std::vector> contours_mask; + std::vector b1_mask; + hg::findContours(mask, contours_mask, b1_mask, cv::RETR_TREE); //提取重叠图像轮廓 + + //过滤非孔洞的联通区域 + std::vector> hole_contours = filterPoly(contours_mask, b1_mask, mask_rotatedRect, m_edgeScale, m_borderSize); + + cv::Scalar color = getBackGroudColor(front(roi_front), rrect_front.size.area()); + for (size_t i = 0; i < hole_contours.size(); i++) + { + std::vector> contourss_temp; + contourss_temp.push_back(hole_contours[i]); + cv::Mat front_temp = front(roi_front); + hg::fillPolys(front_temp, contourss_temp, color); + } + + if (isTwoSide) + { + int width_ = roi_back.width; + roi_back.x = back.cols - roi_back.width - roi_back.x; //因为之前反面图像翻转,所以现在ROI也要进行相应翻转 + color = getBackGroudColor(back(roi_back), rrect_front.size.area()); + for (size_t i = 0; i < hole_contours.size(); i++) + { + std::vector hole_contour; + for (size_t j = 0; j < hole_contours[i].size(); j++) + hole_contour.push_back(cv::Point(width_ - hole_contours[i][j].x - 1, hole_contours[i][j].y)); + + std::vector> contours_temp; + contours_temp.push_back(hole_contour); + cv::Mat back_temp = back(roi_back); + hg::fillPolys(back_temp, contours_temp, color); + } + } +#ifdef LOG + FileTools::write_log("imgprc.txt", "exit ImageOutHole apply"); +#endif // LOG +} + +void CImageApplyOutHole::getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, const cv::Size& srcSize_front, const cv::Size& srcSize_back, cv::Rect& roi_front, + cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect) +{ + cv::Rect roi_front_ = rrect_front.boundingRect(); + cv::Rect roi_back_ = rrect_back.boundingRect(); + + cv::Size meanSize = (roi_front_.size() + roi_back_.size()) / 2; + roi_front_.x += (roi_front_.width - meanSize.width) / 2; + roi_front_.width = meanSize.width; + roi_front_.y += (roi_front_.height - meanSize.height) / 2; + roi_front_.height = meanSize.height; + roi_back_.x += (roi_back_.width - meanSize.width) / 2; + roi_back_.width = meanSize.width; + roi_back_.y += (roi_back_.height - meanSize.height) / 2; + roi_back_.height = meanSize.height; + + mask_rotatedRect.angle = (rrect_front.angle + rrect_back.angle) / 2; + mask_rotatedRect.size = (rrect_front.size + rrect_back.size) / 2.0f; + mask_rotatedRect.center = cv::Point2f(roi_front_.size().width + roi_back_.size().width, roi_front_.size().height + roi_back_.size().height) / 4.0f; + + roi_front = roi_front_ & cv::Rect(cv::Point(0, 0), srcSize_front); + roi_back = roi_back_ & cv::Rect(cv::Point(0, 0), srcSize_back); + + int offset_left_f = roi_front.x - roi_front_.x; + int offset_left_b = roi_back.x - roi_back_.x; + int offset_top_f = roi_front.y - roi_front_.y; + int offset_top_b = roi_back.y - roi_back_.y; + int offset_right_f = roi_front_.br().x - roi_front.br().x; + int offset_right_b = roi_back_.br().x - roi_back.br().x; + int offset_bottom_f = roi_front_.br().y - roi_front.br().y; + int offset_bottom_b = roi_back_.br().y - roi_back.br().y; + + if (offset_left_f > offset_left_b) + { + roi_back.x += offset_left_f - offset_left_b; + roi_back.width -= offset_left_f - offset_left_b; + mask_rotatedRect.center.x -= offset_left_f - offset_left_b; + } + else + { + roi_front.x += offset_left_b - offset_left_f; + roi_front.width -= offset_left_b - offset_left_f; + mask_rotatedRect.center.x -= offset_left_b - offset_left_f; + } + + if (offset_top_f > offset_top_b) + { + roi_back.y += offset_top_f - offset_top_b; + roi_back.height -= offset_top_f - offset_top_b; + mask_rotatedRect.center.y -= offset_top_f - offset_top_b; + } + else + { + roi_front.y += offset_top_b - offset_top_f; + roi_front.height -= offset_top_b - offset_top_f; + mask_rotatedRect.center.y -= offset_top_b - offset_top_f; + } + + if (offset_right_f > offset_right_b) + roi_back.width -= offset_right_f - offset_right_b; + else + roi_front.width -= offset_right_b - offset_right_f; + + if (offset_bottom_f > offset_bottom_b) + roi_back.height -= offset_bottom_f - offset_bottom_b; + else + roi_front.height -= offset_bottom_b - offset_bottom_f; +} + +std::vector> CImageApplyOutHole::filterPoly(std::vector>& contours, const std::vector& m, + cv::RotatedRect roi, float edgeScale, float areaThreshold) +{ + edgeScale = std::min(0.49f, std::max(edgeScale, 0.0f)); + cv::RotatedRect roi2(roi.center, cv::Size(static_cast(roi.size.width * (1 - edgeScale * 2)), + static_cast(roi.size.height * (1 - edgeScale * 2))), roi.angle); + + std::vector vertices_roi1 = hg::getVertices(roi); + std::vector vertices_roi2 = hg::getVertices(roi2); + + std::vector> hole_contours; + for (size_t i = 0, length = contours.size(); i < length; i++) + { + if (m[i][2] != -1) continue; + + cv::RotatedRect rrect = hg::getBoundingRect(contours[i]); + if (rrect.size.area() < areaThreshold) continue; + + bool enabled = true; + for (size_t j = 0, count = contours[i].size(); j < count; j++) + { + cv::Point p(contours[i][j]); + double temp1 = pointPolygonTest(vertices_roi1, p, false); //判断是否在纸张内 1:内;0:上;-1:外 + double temp2 = pointPolygonTest(vertices_roi2, p, false); //判断是否在边缘区域内 1:内;0:上;-1:外 + //如果在纸张外,或者边缘内,视为非孔洞 + if (temp1 < 0 || temp2 > 0) + { + enabled = false; + break; + } + } + + if (enabled) + hole_contours.push_back(contours[i]); + } + return hole_contours; +} + +cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, const std::vector pixelPoints) +{ + if (pixelPoints.empty()) return cv::Scalar(255, 255, 255); + + int channels = image.channels(); + + int temp[3] = { 0 }; + for (size_t i = 0, length = pixelPoints.size(); i < length; ++i) + { + int x = cv::min(cv::max(0, pixelPoints[i].x), image.cols - 1); + int y = cv::min(cv::max(0, pixelPoints[i].y), image.rows - 1); + + const unsigned char* ptr = image.ptr(y, x); + for (int j = 0; j < channels; ++j) + temp[j] += ptr[j]; + } + + return cv::Scalar(temp[0] / static_cast(pixelPoints.size()), + temp[1] / static_cast(pixelPoints.size()), + temp[2] / static_cast(pixelPoints.size())); +} + +cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, int total) +{ + if (image.channels() == 3) + { + cv::Mat image_bgr[3]; + cv::split(image, image_bgr); + + uchar bgr[3]; + for (size_t i = 0; i < 3; i++) + bgr[i] = getBackGroudChannelMean(image_bgr[i], total); + return cv::Scalar(bgr[0], bgr[1], bgr[2]); + } + else + return cv::Scalar::all(getBackGroudChannelMean(image, total)); +} + +uchar CImageApplyOutHole::getBackGroudChannelMean(const cv::Mat& gray, int total) +{ + cv::Mat image_clone; + cv::resize(gray, image_clone, cv::Size(), 0.25, 0.25); + + int threnshold = total / 32; + int channels[] = { 0 }; + int nHistSize[] = { 256 }; + float range[] = { 0, 256 }; + const float* fHistRanges[] = { range }; + cv::Mat hist; + cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, nHistSize, fHistRanges, true, false); + + int hist_array[256]; + for (int i = 0; i < 256; i++) + hist_array[i] = hist.at(i, 0); + + int length = 1; + const int length_max = 255 - m_threshold; + while (length < length_max) + { + for (int i = (int)m_threshold + 1; i < 256 - length; i++) + { + int count = 0; + uint pixSum = 0; + for (int j = 0; j < length; j++) + { + count += hist_array[j + i]; + pixSum += hist_array[j + i] * (i + j); + } + + if (count >= threnshold) + return pixSum / count; + } + length++; + } + return 255; +} \ No newline at end of file diff --git a/app/modules/imgproc/ImageProcess/ImageApplyOutHole.h b/app/modules/imgproc/ImageProcess/ImageApplyOutHole.h new file mode 100644 index 0000000..9dfa931 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageApplyOutHole.h @@ -0,0 +1,76 @@ +/* + * ==================================================== + + * 功能:装订孔填充 + * 作者:刘丁维 + * 生成时间:2020/11/21 + * 最近修改时间:2020/05/12 v1.0 + * 2020/11/17 v1.1 + * 2021/09/06 v1.2 调整默认二值化阈值,从原来的50调整为100。将填充颜色从局部颜色提取改为全局颜色提取。 + * 2021/11/03 v1.3 增加逻辑,如果正反面图像尺寸差异超过10个像素,直接返回,不再进行除穿孔处理。 + * 2021/11/04 v1.4 增加背景抗噪机制,能够抗5像素的背景噪声。 + * 2021/11/17 v1.5 调整代码格式,避免一些由于opencv版本导致的BUG。 + * 2022/04/18 v1.6 修复由于图像超出边界导致的定位孔洞异常的BUG。 + * 2022/05/04 v1.6.1 增加逻辑判断,如果出现黑图,直接返回,不对原图进行任何处理。 + * 版本号:v1.6.1 + + * ==================================================== + */ + +#ifndef IMAGE_APPLY_OUT_HOLE_H +#define IMAGE_APPLY_OUT_HOLE_H + +#include "ImageApply.h" + +class CImageApplyOutHole : public CImageApply +{ +public: + + CImageApplyOutHole(); + + /* + * borderSize [in]:孔洞面积阈值 + * edgeScale [in]:纸张边缘区域比例,取值范围(0,0.5),默认值0.1 + * threshold [in]:二值化阈值 + */ + CImageApplyOutHole(float borderSize, float edgeScale, double threshold); + + ~CImageApplyOutHole(void); + + virtual void apply(std::vector& mats, bool isTwoSide); + + float getBorderSize() { return m_borderSize; } + + float getEdgeScale() { return m_edgeScale; } + + double getThreshold() { return m_threshold; } + + void setBorderSize(float size) { m_borderSize = size; } + + void setEdgeScale(float scale) { m_edgeScale = scale; } + + void setThreshold(double threshold) { m_threshold = (std::min)((std::max)(threshold, 1.0), 254.0); } + +private: + + virtual void apply(cv::Mat& pDib, int side); + + void getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, const cv::Size& srcSize_front, const cv::Size& srcSize_back, cv::Rect& roi_front, + cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect); + + std::vector > filterPoly(std::vector>& contours, const std::vector& m, cv::RotatedRect roi, + float edgeScale, float areaThreshold); + + cv::Scalar getBackGroudColor(const cv::Mat& image, const std::vector pixelPoints); + + cv::Scalar getBackGroudColor(const cv::Mat& image, int total); + + uchar getBackGroudChannelMean(const cv::Mat& gray, int total); + +private: + float m_borderSize; + float m_edgeScale; + double m_threshold; +}; + +#endif // !IMAGE_APPLY_OUT_HOLE_H diff --git a/app/modules/imgproc/ImageProcess/ImageProcess_Public.cpp b/app/modules/imgproc/ImageProcess/ImageProcess_Public.cpp new file mode 100644 index 0000000..30bc790 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageProcess_Public.cpp @@ -0,0 +1,349 @@ +#include "ImageProcess_Public.h" + +namespace hg +{ + void convexHull(const std::vector& src, std::vector& dst, bool clockwise) + { + CvMemStorage* storage = cvCreateMemStorage(); // + CvSeq* ptseq = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage); //ptseqstorage + + //将src的点集填充至ptseq + for (const cv::Point& item : src) + { + CvPoint p; + p.x = item.x; + p.y = item.y; + cvSeqPush(ptseq, &p); + } + + //获取轮廓点 + CvSeq* hull = cvConvexHull2(ptseq, nullptr, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 0); + + if (hull == nullptr) + { + //释放storage + cvReleaseMemStorage(&storage); + return; + } + + //填充dst + dst.clear(); + for (int i = 0, hullCount = hull->total; i < hullCount; i++) + dst.push_back(**CV_GET_SEQ_ELEM(CvPoint*, hull, i)); + + //释放storage + cvReleaseMemStorage(&storage); + } + +#define R_COLOR 255 + void fillConvexHull(cv::Mat& image, const std::vector& points) + { + uint index_top = 0; + uint index_bottom = 0; + for (size_t i = 0, length = points.size(); i < length; i++) + { + if (points[i].y < points[index_top].y) + index_top = i; + if (points[i].y > points[index_bottom].y) + index_bottom = i; + } + + std::vector edge_left; + uint temp = index_top; + while (temp != index_bottom) + { + edge_left.push_back(points[temp]); + temp = (temp + points.size() - 1) % points.size(); + } + edge_left.push_back(points[index_bottom]); + + std::vector edge_right; + temp = index_top; + while (temp != index_bottom) + { + edge_right.push_back(points[temp]); + temp = (temp + points.size() + 1) % points.size(); + } + edge_right.push_back(points[index_bottom]); + + std::vector left_edge_x; + std::vector left_edge_y; + for (size_t i = 0, length = edge_left.size() - 1; i < length; i++) + { + int y_top = edge_left[i].y; + int x_top = edge_left[i].x; + int y_bottom = edge_left[i + 1].y; + int x_bottom = edge_left[i + 1].x; + for (int y = y_top; y < y_bottom; y++) + if (y >= 0 && y_top != y_bottom && y < image.rows) + { + left_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top)); + left_edge_y.push_back(y); + } + } + size_t step = image.step; + unsigned char* ptr; + ptr = image.data + static_cast(left_edge_y[0]) * step; + for (size_t i = 0, length = left_edge_x.size(); i < length; i++) + { + int pix = left_edge_x[i]; + if (pix < image.cols - 1 && pix > 0) + memset(ptr + i * step, R_COLOR, static_cast((pix + 1) * image.channels())); + } + + std::vector right_edge_x; + std::vector right_edge_y; + for (size_t i = 0, length = edge_right.size() - 1; i < length; i++) + { + int y_top = edge_right[i].y; + int x_top = edge_right[i].x; + int y_bottom = edge_right[i + 1].y; + int x_bottom = edge_right[i + 1].x; + for (int y = y_top; y < y_bottom; y++) + if (y_top != y_bottom && y < image.rows && y >= 0) + { + right_edge_x.push_back(((x_bottom - x_top) * y + x_top * y_bottom - x_bottom * y_top) / (y_bottom - y_top)); + right_edge_y.push_back(y); + } + } + + ptr = image.data + static_cast(right_edge_y[0]) * step; + for (size_t i = 0, length = right_edge_x.size(); i < length; i++) + { + int pix = right_edge_x[i]; + if (pix < image.cols - 1 && pix > 0) + memset(ptr + i * step + pix * image.channels(), R_COLOR, step - static_cast(pix * image.channels())); + } + + if (edge_left[0].y > 0) + memset(image.data, R_COLOR, static_cast(edge_left[0].y) * step); + + if (edge_left.back().y < image.rows - 1) + memset(image.data + static_cast(edge_left.back().y) * step, R_COLOR, + static_cast(image.rows - edge_left.back().y) * step); + } + + void fillPolys(cv::Mat& image, const std::vector>& contours, const cv::Scalar& color) + { + if (contours.empty()) return; + + size_t count = contours.size(); + cv::Point** pointss = new cv::Point*[count]; + int* npts = new int[count]; + + for (size_t i = 0; i < count; i++) + { + size_t length = contours[i].size(); + npts[i] = length; + pointss[i] = new cv::Point[length]; + for (size_t j = 0; j < length; j++) + pointss[i][j] = contours[i][j]; + } + cv::fillPoly(image, const_cast(pointss), npts, count, color); + + for (size_t i = 0; i < count; i++) + delete[] pointss[i]; + + delete[] pointss; + delete[] npts; + } + + void findContours(const cv::Mat& src, std::vector>& contours, std::vector& hierarchy, int retr, int method, cv::Point offset) + { +#if CV_VERSION_REVISION <= 6 + CvMat c_image = src; +#else + CvMat c_image; + c_image = cvMat(src.rows, src.cols, src.type(), src.data); + c_image.step = src.step[0]; + c_image.type = (c_image.type & ~cv::Mat::CONTINUOUS_FLAG) | (src.flags & cv::Mat::CONTINUOUS_FLAG); +#endif + cv::MemStorage storage(cvCreateMemStorage()); + CvSeq* _ccontours = nullptr; + +#if CV_VERSION_REVISION <= 6 + cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint(offset)); +#else + cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint{ offset.x, offset.y }); +#endif + if (!_ccontours) + { + contours.clear(); + return; + } + cv::Seq all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage)); + size_t total = all_contours.size(); + contours.resize(total); + + cv::SeqIterator it = all_contours.begin(); + for (size_t i = 0; i < total; i++, ++it) + { + CvSeq* c = *it; + reinterpret_cast(c)->color = static_cast(i); + int count = c->total; + int* data = new int[static_cast(count * 2)]; + cvCvtSeqToArray(c, data); + for (int j = 0; j < count; j++) + { + contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1])); + } + delete[] data; + } + + hierarchy.resize(total); + it = all_contours.begin(); + for (size_t i = 0; i < total; i++, ++it) + { + CvSeq* c = *it; + int h_next = c->h_next ? reinterpret_cast(c->h_next)->color : -1; + int h_prev = c->h_prev ? reinterpret_cast(c->h_prev)->color : -1; + int v_next = c->v_next ? reinterpret_cast(c->v_next)->color : -1; + int v_prev = c->v_prev ? reinterpret_cast(c->v_prev)->color : -1; + hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev); + } + + storage.release(); + } + + cv::RotatedRect getBoundingRect(const std::vector& contour) + { + if (contour.empty()) return {}; + + cv::RotatedRect rect = minAreaRect(contour); + if (rect.angle < -45) + { + rect.angle += 90; + float temp = rect.size.width; + rect.size.width = rect.size.height; + rect.size.height = temp; + } + if (rect.angle > 45) + { + rect.angle -= 90; + float temp = rect.size.width; + rect.size.width = rect.size.height; + rect.size.height = temp; + } + + return rect; + } + + std::vector getMaxContour(const std::vector>& contours, const std::vector& hierarchy) + { + std::vector maxContour; + if (contours.size() < 1) return {}; + + for (size_t i = 0, length = hierarchy.size(); i < length; i++) + if (hierarchy[i][3] == -1) + for (const auto &item : contours[i]) + maxContour.push_back(item); + + return maxContour; + } + + std::vector getVertices(const cv::RotatedRect& rect) + { + cv::Point2f box[4]; + rect.points(box); + std::vector points; + for (int i = 0; i < 4; i++) + points.push_back(cv::Point(box[i])); + + return points; + } + + void polyIndent(std::vector& points, const cv::Point& center, int indent) + { + static cv::Point zero(0, 0); + for (cv::Point& item : points) + { +#if 0 + cv::Point vec = item - center; + if (vec != zero) + { + int length = vec.x * vec.x + vec.y * vec.y; + float x = cv::sqrt(static_cast(vec.x * vec.x / length)) * indent; + float y = cv::sqrt(static_cast(vec.y * vec.y / length)) * indent; + + if (vec.x < 0) x *= -1.0f; + if (vec.y < 0) y *= -1.0f; + + item.x -= static_cast(x); + item.y -= static_cast(y); + } +#else + if (item.x > center.x) + item.x -= indent; + else + item.x += indent; + + if (item.y > center.y) + item.y -= indent; + else + item.y += indent; +#endif + } + } + + cv::Mat transforColor(const cv::Mat& src) + { + if (src.channels() == 1) return src.clone(); + + std::vector channels(3); + cv::split(src, channels); + + cv::Mat temp, dst; + bitwise_or(channels[0], channels[1], temp); + bitwise_or(channels[2], temp, dst); + temp.release(); + + for (cv::Mat& index : channels) + index.release(); + return dst; + } + + void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre) + { + if (src.channels() == 3) + { +#ifdef USE_ONENCL + if (cl_res.context) + transforColor_threshold_opencl(src, dst, static_cast(thre)); + else +#endif + { + cv::Mat gray = transforColor(src); + cv::threshold(gray, dst, thre, 255, cv::THRESH_BINARY); + gray.release(); + } + } + else + cv::threshold(src, dst, thre, 255, cv::THRESH_BINARY); + } + + cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat) + { + double src_data[3] = { static_cast(p.x), static_cast(p.y), 1 }; + cv::Mat src(3, 1, warp_mat.type(), src_data); //warp_mat.type() == CV_64FC1 + + cv::Mat dst = warp_mat * src; + double* ptr = reinterpret_cast(dst.data); + return cv::Point(static_cast(ptr[0]), static_cast(ptr[1])); + } + + int distanceP2P(const cv::Point& p1, const cv::Point& p2) + { + return cv::sqrt(cv::pow(p1.x - p2.x, 2) + cv::pow(p1.y - p2.y, 2)); + } + + float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2) + { + //求直线方程 + int A = 0, B = 0, C = 0; + A = l1.y - l2.y; + B = l2.x - l1.x; + C = l1.x * l2.y - l1.y * l2.x; + //代入点到直线距离公式 + return ((float)abs(A * p.x + B * p.y + C)) / ((float)sqrtf(A * A + B * B)); + } +} \ No newline at end of file diff --git a/app/modules/imgproc/ImageProcess/ImageProcess_Public.h b/app/modules/imgproc/ImageProcess/ImageProcess_Public.h new file mode 100644 index 0000000..96acb28 --- /dev/null +++ b/app/modules/imgproc/ImageProcess/ImageProcess_Public.h @@ -0,0 +1,130 @@ +/* + * ==================================================== + + * 功能:公共图像处理算法。部分功能可能会在ImageProcess里面多个类反复使用 + * 作者:刘丁维 + * 生成时间:2020/4/21 + * 最近修改时间:2020/4/21 + * 2021/07/12 v1.1 getBoundingRect中,增加考虑纠正初始 angle > 90 的情况。 + * 2021/07/22 v1.2 convexHull中,修复点集为空可能导致崩溃的BUG。 + * 版本号:v1.2 + + * ==================================================== + */ + +#ifndef IMAGE_PROCESS_PUBLIC_H +#define IMAGE_PROCESS_PUBLIC_H + +#include "opencv2/opencv.hpp" +#include + +namespace hg +{ + /* + * 功能:计算源点集的凸多边形轮廓,输出轮廓点集 + * src: 源点集 + * dst: 目标点集 + * clockwise: true为顺时针排序,false为逆时针排序 + */ + void convexHull(const std::vector& src, std::vector& dst, bool clockwise = false); + + /* + * 功能:填充凸多边形,默认颜色为白色 + * image: 填充图像 + * points: 凸多边形轮廓点集(逆时针排序) + */ + void fillConvexHull(cv::Mat& image, const std::vector& points); + + /* + * 功能:填充凹多边形 + * image: 填充图像 + * contours: 凹多边形轮廓点集(逆时针排序) + * color: 填充颜色 + */ + void fillPolys(cv::Mat& image, const std::vector>& contours, const cv::Scalar& color); + + /* + * 功能:获取连通区域轮廓 + * src: 源图像 + * contours: 结果轮廓集 + * hierarchy: 轮廓集的排序关系。与contours的数量对应,受retr选项不同,排序会有变化 + * retr: 轮廓集排序方式,默认为链式排序 + * method: 查找算法选择,默认为普通查找 + * offset: 查找起始点,默认为(0,0)点 + */ + void findContours(const cv::Mat& src, std::vector>& contours, std::vector& hierarchy, + int retr = cv::RETR_LIST, int method = cv::CHAIN_APPROX_SIMPLE, cv::Point offset = cv::Point(0, 0)); + + /* + * 功能:获取覆盖点集的最小外接矩形 + * contour: 点集 + * 返回值: 旋转矩形 + */ + cv::RotatedRect getBoundingRect(const std::vector& contour); + + /* + * 功能: 获取覆盖轮廓集的最小外接凸多边形轮廓 + * contours: 轮廓集(每个轮廓由点集组成) + * hierarchy: 轮廓集中,轮廓之间的关系。数量与contours对应 + * 返回值: 凸多边形轮廓点集 + */ + std::vector getMaxContour(const std::vector>& contours, const std::vector& hierarchy); + + /* + * 功能: 获取覆盖轮廓集的最小外接凸多边形轮廓 + * contours: 轮廓集(每个轮廓由点集组成) + * hierarchy: 轮廓集中,轮廓之间的关系。数量与contours对应 + * 返回值: 凸多边形轮廓点集 + */ + std::vector getVertices(const cv::RotatedRect& rect); + + /* + * 功能: 轮廓缩进 + * points: 轮廓点集 + * center: 围绕center点缩进 + * indent: 缩进像素 + */ + void polyIndent(std::vector& points, const cv::Point& center, int indent); + + /* + * 功能: 二值化,能够处理彩色和灰度图像。src为彩色图像时,灰度图取三个通道的最大值 + * src: 源图 + * dst: 目标图 + * thre: 阈值 + */ + void threshold_Mat(const cv::Mat& src, cv::Mat& dst, double thre); + + /* + * 功能: 彩色转灰度,灰度图取三个通道的最大值 + * src: 源图 + * 返回值: 灰度图 + */ + cv::Mat transforColor(const cv::Mat& src); + + /* + * 功能: 获取点的仿射变换 + * p: 原点 + * warp_mat: 仿射变换系数矩阵 + * 返回值: 变换后的点 + */ + cv::Point warpPoint(const cv::Point& p, const cv::Mat& warp_mat); + + /* + * 功能: 点到点距离 + * p1: 点1 + * p2: 点2 + * 返回值: 点到点距离 + */ + int distanceP2P(const cv::Point& p1, const cv::Point& p2); + + /* + * 功能: 点到直线距离 + * p: 点 + * l1: 直线端点1 + * l2: 直线端点2 + * 返回值: 点到直线距离 + */ + float distanceP2L(const cv::Point& p, const cv::Point& l1, const cv::Point& l2); +} + +#endif // !IMAGE_PROCESS_C_H diff --git a/app/release/x64/HGBase.dll b/app/release/x64/HGBase.dll new file mode 100644 index 0000000..a697ec4 Binary files /dev/null and b/app/release/x64/HGBase.dll differ diff --git a/app/release/x64/HGImgFmt.dll b/app/release/x64/HGImgFmt.dll new file mode 100644 index 0000000..f16584b Binary files /dev/null and b/app/release/x64/HGImgFmt.dll differ diff --git a/app/release/x64/HGImgProc.dll b/app/release/x64/HGImgProc.dll new file mode 100644 index 0000000..303f91c Binary files /dev/null and b/app/release/x64/HGImgProc.dll differ diff --git a/app/release/x86/HGBase.dll b/app/release/x86/HGBase.dll new file mode 100644 index 0000000..c686294 Binary files /dev/null and b/app/release/x86/HGBase.dll differ diff --git a/app/release/x86/HGImgFmt.dll b/app/release/x86/HGImgFmt.dll new file mode 100644 index 0000000..aa0fa6a Binary files /dev/null and b/app/release/x86/HGImgFmt.dll differ diff --git a/app/release/x86/HGImgProc.dll b/app/release/x86/HGImgProc.dll new file mode 100644 index 0000000..601a8e6 Binary files /dev/null and b/app/release/x86/HGImgProc.dll differ diff --git a/app/release/x86/HGPdtToolDb.dll b/app/release/x86/HGPdtToolDb.dll new file mode 100644 index 0000000..ec001e4 Binary files /dev/null and b/app/release/x86/HGPdtToolDb.dll differ diff --git a/app/release/x86/libmysql.dll b/app/release/x86/libmysql.dll new file mode 100644 index 0000000..399d204 Binary files /dev/null and b/app/release/x86/libmysql.dll differ diff --git a/app/sdk/include/base/HGBase.h b/app/sdk/include/base/HGBase.h new file mode 100644 index 0000000..afcd65f --- /dev/null +++ b/app/sdk/include/base/HGBase.h @@ -0,0 +1,24 @@ +#ifndef __HGBASE_H__ +#define __HGBASE_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" +#include "HGBase64.h" +#include "HGDes.h" +#include "HGMd5.h" +#include "HGLock.h" +#include "HGEvent.h" +#include "HGDll.h" +#include "HGLog.h" +#include "HGConsole.h" +#include "HGBuffer.h" +#include "HGImage.h" +#include "HGThread.h" +#include "HGUtility.h" +#include "HGInfo.h" +#include "HGIni.h" +#include "HGMsgPump.h" +#include "HGTime.h" +#include "HGNamedPipe.h" + +#endif /* __HGBASE_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGBase64.h b/app/sdk/include/base/HGBase64.h new file mode 100644 index 0000000..2b8c120 --- /dev/null +++ b/app/sdk/include/base/HGBase64.h @@ -0,0 +1,34 @@ +#ifndef __HGBASE64_H__ +#define __HGBASE64_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* Base64编码 +* 参数: +* 1) originalData: in, 原始数据地址 +* 2) originalSize: in, 原始数据长度 +* 3) base64Data: out, base64地址 +* 4) base64Size: out, 编码后base64长度 +* 说明: +* 1) 该函数的调用需要分两次,第一次base64Data为NULL,base64Size不为NULL, 获取编码后base64长度 +* 2) 分配足够的内存后,然后调用第二次,此时base64Data为分配的地址 +*/ +HGEXPORT HGResult HGAPI HGBase_Base64Encode(const HGByte* originalData, HGSize originalSize, + HGByte* base64Data, HGSize* base64Size); + +/* Base64解码 +* 参数: +* 1) base64Data: in, base64地址 +* 2) base64Size: in, base64长度 +* 3) originalData: out, 原始数据地址 +* 4) originalSize: out, 解码后原始数据长度 +* 说明: +* 1) 该函数的调用需要分两次,第一次originalData为NULL,originalSize不为NULL, 获取解码后原始数据长度 +* 2) 分配足够的内存后,然后调用第二次,此时originalData为分配的地址 +* 3) base64Data中的数据必须是标准Base64字符, 不能有其他字符,比如\r或\n等 +*/ +HGEXPORT HGResult HGAPI HGBase_Base64Decode(const HGByte* base64Data, HGSize base64Size, + HGByte* originalData, HGSize* originalSize); + +#endif /* __HGBASE64_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGBaseErr.h b/app/sdk/include/base/HGBaseErr.h new file mode 100644 index 0000000..b06338e --- /dev/null +++ b/app/sdk/include/base/HGBaseErr.h @@ -0,0 +1,40 @@ +#ifndef __HGBASEERR_H__ +#define __HGBASEERR_H__ + +/* 无错误 */ +#define HGBASE_ERR_OK 0x00000000L + +/* 一般错误 */ +#define HGBASE_ERR_FAIL 0x00000001L + +/* 内存不足 */ +#define HGBASE_ERR_OUTOFMEMORY 0x00000002L + +/* 参数非法 */ +#define HGBASE_ERR_INVALIDARG 0x00000003L + +/* 无访问权限 */ +#define HGBASE_ERR_ACCESSDENIED 0x00000004L + +/* 数据非法 */ +#define HGBASE_ERR_INVALIDDATA 0x00000005L + +/* 未实现 */ +#define HGBASE_ERR_NOTIMPL 0x00000006L + +/* 不支持该功能 */ +#define HGBASE_ERR_NOTSUPPORT 0x00000007L + +/* 超时 */ +#define HGBASE_ERR_TIMEOUT 0x00000008L + +/* 文件不存在 */ +#define HGBASE_ERR_FILENOTEXIST 0x00000009L + +/* 加载动态库失败 */ +#define HGBASE_ERR_LOADLIBRARY 0x0000000AL + +/* 文件错误 */ +#define HGBASE_ERR_FILEERROR 0x0000000BL + +#endif /* __HGBASEERR_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGBuffer.h b/app/sdk/include/base/HGBuffer.h new file mode 100644 index 0000000..0856aa2 --- /dev/null +++ b/app/sdk/include/base/HGBuffer.h @@ -0,0 +1,76 @@ +#ifndef __HGBUFFER_H__ +#define __HGBUFFER_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGBuffer); + +/* 创建新的缓冲区 +* 参数: +* 1) size: in, 缓冲区大小, 单位字节 +* 2) buffer: out, 新缓冲区句柄 +* 说明: +* 1) 内部会分配size字节大小的内存 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateBuffer(HGUSize size, HGBuffer* buffer); + +/* 通过已有数据创建新的缓冲区 +* 参数: +* 1) data: in, 已有的数据地址 +* 2) size: in, 已有的数据大小, 单位字节 +* 3) buffer: out, 新缓冲区句柄 +* 说明: +* 1) 内部会分配size字节大小的内存, 新的缓冲区创建完成时, 会将data中的数据拷贝过去 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateBufferFromData(const HGByte* data, HGUSize size, HGBuffer* buffer); + +/* 通过已有数据创建新的缓冲区(不分配内存, 不拷贝数据) +* 参数: +* 1) data: in, 已有的数据地址 +* 2) size: in, 已有的数据大小, 单位字节 +* 3) buffer: out, 新缓冲区句柄 +* 说明: +* 1) 内部不会分配内存, 将直接使用原始数据 +* 2) 需保证缓冲区销毁前原始数据一直有效 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateBufferWithData(HGByte* data, HGUSize size, HGBuffer* buffer); + +/* 通过现有缓冲区创建新的缓冲区 +* 参数: +* 1) srcBuffer: in, 已有缓冲区 +* 2) buffer: out, 新缓冲区句柄 +* 说明: +* 1) 内部会分配现有缓冲区的size字节大小的内存, 新缓冲区创建完成时, 会将现有缓冲区中的数据拷贝过去 +*/ +HGEXPORT HGResult HGAPI HGBase_CloneBuffer(HGBuffer srcBuffer, HGBuffer* buffer); + +/* 销毁缓冲区 +* 参数: +* 1) buffer: in, 缓冲区句柄 +* 说明: +* 1) 如果内部分配了内存, 销毁的时候会自动释放该内存 +*/ +HGEXPORT HGResult HGAPI HGBase_DestroyBuffer(HGBuffer buffer); + +/* 获取缓冲区数据地址 +* 参数: +* 1) buffer: in, 缓冲区句柄 +* 2) data: out, 数据地址 +* 说明: +* 1) 如果内部分配了内存, 返回的是分配的内存地址 +* 2) 如果内部没有分配内存, 返回的则是原始数据的地址 +*/ +HGEXPORT HGResult HGAPI HGBase_GetBufferData(HGBuffer buffer, HGByte** data); + +/* 获取缓冲区数据大小 +* 参数: +* 1) buffer: in, 缓冲区句柄 +* 2) size: out, 数据长度 +* 说明: +* 1) 如果内部分配了内存, 返回的是分配的内存大小 +* 2) 如果内部没有分配内存, 返回的则是原始数据的大小 +*/ +HGEXPORT HGResult HGAPI HGBase_GetBufferSize(HGBuffer buffer, HGUSize* size); + +#endif /* __HGBUFFER_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGConsole.h b/app/sdk/include/base/HGConsole.h new file mode 100644 index 0000000..566f4ae --- /dev/null +++ b/app/sdk/include/base/HGConsole.h @@ -0,0 +1,32 @@ +#ifndef __HGCONSOLE_H__ +#define __HGCONSOLE_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGConsole); + +/* 开启控制台 +* 参数: +* 1) log: out, 控制台句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_OpenConsole(HGConsole *console); + +/* 关闭控制台 +* 参数: +* 1) log: in, 控制台句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_CloseConsole(HGConsole console); + +/* 写控制台信息 +* 参数: +* 1) log: in, 控制台句柄 +* 2) info: in, 信息, 一次一行, info无需加换行符 +* 说明: +* 1) 该函数不是线程安全的, 在不同线程调用的时候, 需要加锁 +*/ +HGEXPORT HGResult HGAPI HGBase_WriteConsole(HGConsole console, const HGChar* info); + +#endif /* __HGCONSOLE_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGCrash.h b/app/sdk/include/base/HGCrash.h new file mode 100644 index 0000000..69045d6 --- /dev/null +++ b/app/sdk/include/base/HGCrash.h @@ -0,0 +1,13 @@ +#ifndef __HGCRASH_H__ +#define __HGCRASH_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +typedef void (HGAPI *HGCrashFunc)(HGPointer crashAddr, HGPointer param); + +HGEXPORT HGResult HGAPI HGBase_RegisterCrashFunc(HGCrashFunc func, HGPointer param); + +HGEXPORT HGResult HGAPI HGBase_MakeCrashFile(const HGChar *filePath); + +#endif /* __HGCRASH_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGDef.h b/app/sdk/include/base/HGDef.h new file mode 100644 index 0000000..76d6036 --- /dev/null +++ b/app/sdk/include/base/HGDef.h @@ -0,0 +1,146 @@ +#ifndef __HGDEF_H__ +#define __HGDEF_H__ + +/**************************************************************************** + * Platform Dependent Definitions and Typedefs * + ****************************************************************************/ + + /* Microsoft C/C++ Compiler */ +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) || defined (_WINDOWS) + + #define HG_CMP_MSC + #if defined(_WIN64) || defined(WIN64) + #define HG_64BIT + #elif defined(_WIN32) || defined(WIN32) + #define HG_32BIT + #endif + +/* Apple Compiler (which is GNU now) */ +#elif defined(__APPLE__) + + #define HG_CMP_XCODE + #define HG_64BIT + +/* GNU C/C++ Compiler */ +#elif defined(__GNUC__) + + #define HG_CMP_GNU + #if defined(__alpha__) || defined(__ia64__) || defined(__ppc64__) || defined(__s390x__) || defined(__x86_64__) + #define HG_64BIT + #else + #define HG_32BIT + #endif + +/* Unrecognized */ +#else + + #error Unrecognized compiler + +#endif + +#if defined(HG_CMP_MSC) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif +#endif + +/* type defines */ +typedef void HGVoid; +typedef char HGChar; +typedef unsigned char HGByte; +typedef short HGShort; +typedef unsigned short HGUShort; +typedef int HGInt; +typedef unsigned int HGUInt; +typedef long long HGLonglong; +typedef unsigned long long HGULonglong; +typedef void* HGPointer; +typedef HGInt HGBool; +typedef float HGFloat; +typedef double HGDouble; +#ifdef HG_64BIT + typedef HGLonglong HGSize; + typedef HGULonglong HGUSize; +#else + typedef HGInt HGSize; + typedef HGUInt HGUSize; +#endif + +typedef HGUInt HGColor; + +#define HG_MAKECOLOR(r, g, b, a) (HGColor)(((HGUInt)a << 24) | ((HGUInt)b << 16) | ((HGUInt)g << 8) | (HGUInt)r) +#define HG_GETCOLOR_R(color) (HGUInt)((HGColor)color & 0xFF) +#define HG_GETCOLOR_G(color) (HGUInt)(((HGColor)color >> 8) & 0xFF) +#define HG_GETCOLOR_B(color) (HGUInt)(((HGColor)color >> 16) & 0xFF) +#define HG_GETCOLOR_A(color) (HGUInt)(((HGColor)color >> 24) & 0xFF) + +/* error code */ +typedef HGUInt HGResult; + +#define HGTRUE 1 +#define HGFALSE 0 + +#ifndef HGMAX + #define HGMAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef HGMIN + #define HGMIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#if defined(HG_CMP_MSC) + #ifdef __cplusplus + #define HGEXPORT extern "C" + #else + #define HGEXPORT + #endif /* __cplusplus */ + #define HGAPI __stdcall + #define HGAPIV __cdecl +#else + #ifdef __cplusplus + #define HGEXPORT extern "C" __attribute ((visibility("default"))) + #else + #define HGEXPORT __attribute ((visibility("default"))) + #endif /* __cplusplus */ + #define HGAPI + #define HGAPIV +#endif + +#define HG_DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGInt left; + HGInt top; + HGInt right; + HGInt bottom; +}HGRect; + +typedef struct +{ + HGFloat left; + HGFloat top; + HGFloat right; + HGFloat bottom; +}HGRectF; + +typedef struct +{ + HGInt x; + HGInt y; +}HGPoint; + +typedef struct +{ + HGFloat x; + HGFloat y; +}HGPointF; + +#pragma pack(pop) + +#endif /* __HGDEF_H__ */ diff --git a/app/sdk/include/base/HGDes.h b/app/sdk/include/base/HGDes.h new file mode 100644 index 0000000..f246065 --- /dev/null +++ b/app/sdk/include/base/HGDes.h @@ -0,0 +1,27 @@ +#ifndef __HGDES_H__ +#define __HGDES_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* DES加密 +* 参数: +* 1) data: in, out, 明文 +* 2) size: in, 明文尺寸, 必须是8的倍数 +* 3) key: in, 加密密钥, 为8字节数组 +* 说明: +* 1) 加密后的密文会覆盖明文,如果需要保留明文,需要提前保存 +*/ +HGEXPORT HGResult HGAPI HGBase_DesEncrypt(HGByte* data, HGUInt size, const HGByte* key); + +/* DES解密 +* 参数: +* 1) data: in, out, 密文 +* 2) size: in, 密文尺寸, 必须是8的倍数 +* 3) key: in, 解密密钥, 为8字节数组 +* 说明: +* 1) 解密后的明文会覆盖密文,如果需要保留密文,需要提前保存 +*/ +HGEXPORT HGResult HGAPI HGBase_DesDecrypt(HGByte* data, HGUInt size, const HGByte* key); + +#endif /* __HGDES_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGDll.h b/app/sdk/include/base/HGDll.h new file mode 100644 index 0000000..00e78d1 --- /dev/null +++ b/app/sdk/include/base/HGDll.h @@ -0,0 +1,35 @@ +#ifndef __HGDLL_H__ +#define __HGDLL_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGDll); + +/* 加载DLL +* 参数: +* 1) fileName: in, dll/so文件路径, 可以是绝对路径或相对路径 +* 2) dll: out, DLL句柄 +* 说明: +* 1) 在windows系统上, fileName需要是GBK编码 +* 2) 在linux系统上, fileName需要是UTF8编码 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateDll(const HGChar* fileName, HGDll* dll); + +/* 销毁DLL +* 参数: +* 1) dll: in, DLL句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_DestroyDll(HGDll dll); + +/* 查找函数地址 +* 参数: +* 1) dll: in, DLL句柄 +* 2) symbol: in, 函数名 +* 3) func: out, 函数地址 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_GetDllProcAddress(HGDll dll, const HGChar* symbol, HGPointer* func); + +#endif /* __HGDLL_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGEvent.h b/app/sdk/include/base/HGEvent.h new file mode 100644 index 0000000..205afc5 --- /dev/null +++ b/app/sdk/include/base/HGEvent.h @@ -0,0 +1,60 @@ +#ifndef __HGEVENT_H__ +#define __HGEVENT_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGEvent); + +/* 创建事件 +* 参数: +* 1) manualReset: in, 是否手动设置 +* 2) initState: in, 初始化时是否有信号 +* 3) event: out, 事件句柄 +* 说明: +* 1) 当manualReset为HGTRUE时, HGBase_WaitEvent和HGBase_WaitEventTimeout调用后, 事件仍然为有信号 +* 2) 当manualReset为HGFALSE时, HGBase_WaitEvent和HGBase_WaitEventTimeout调用后, 事件为无信号 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateEvent(HGBool manualReset, HGBool initState, HGEvent* event); + +/* 销毁事件 +* 参数: +* 1) event: in, 事件句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_DestroyEvent(HGEvent event); + +/* 无限等待事件 +* 参数: +* 1) event: in, 事件句柄 +* 说明: +* 1) 如果创建时的manualReset为HGTRUE, 返回前不会将事件置为无信号;否则,返回前会将事件置为无信号 +*/ +HGEXPORT HGResult HGAPI HGBase_WaitEvent(HGEvent event); + +/* 等待事件, 带超时时间 +* 参数: +* 1) event: in, 事件句柄 +* 2) milliseconds: in, 超时时间, 毫秒 +* 说明: +* 1) 在milliseconds时间内如果事件有信号,立即返回 +* 2) 如果一直无信号, 在milliseconds毫秒后也立即返回, 返回值为HGBASE_ERR_WAIT_TIMEOUT +* 3) 如果创建时的manualReset为HGTRUE, 返回前不会将事件置为无信号;否则,返回前会将事件置为无信号 +*/ +HGEXPORT HGResult HGAPI HGBase_WaitEventTimeout(HGEvent event, HGUInt milliseconds); + +/* 使事件有信号 +* 参数: +* 1) event: in, 事件句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_SetEvent(HGEvent event); + +/* 使事件无信号 +* 参数: +* 1) event: in, 事件句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_ResetEvent(HGEvent event); + +#endif /* __HGEVENT_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGImage.h b/app/sdk/include/base/HGImage.h new file mode 100644 index 0000000..cd87fdf --- /dev/null +++ b/app/sdk/include/base/HGImage.h @@ -0,0 +1,391 @@ +#ifndef __HGIMAGE_H__ +#define __HGIMAGE_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" +#if defined(HG_CMP_MSC) +#include +#endif + +HG_DECLARE_HANDLE(HGImage); + +/* 1位黑白图 */ +#define HGBASE_IMGTYPE_BINARY 1L +/* 8位灰度图 */ +#define HGBASE_IMGTYPE_GRAY 2L +/* 24位真彩色,B8G8R8格式 */ +#define HGBASE_IMGTYPE_BGR 3L +/* 24位真彩色,R8G8B8格式 */ +#define HGBASE_IMGTYPE_RGB 4L +/* 32位真彩色,带Alpha通道,B8G8R8A8格式 */ +#define HGBASE_IMGTYPE_BGRA 5L +/* 32位真彩色,带Alpha通道,R8G8B8A8格式 */ +#define HGBASE_IMGTYPE_RGBA 6L + +/* 顶左结构 */ +#define HGBASE_IMGORIGIN_TOP 1L +/* 底左结构 */ +#define HGBASE_IMGORIGIN_BOTTOM 2L + +#pragma pack(push) +#pragma pack(4) + +/* 图像信息 */ +typedef struct +{ + HGUInt width; /* 宽(像素),列数 */ + HGUInt height; /* 高(像素),行数 */ + HGUInt type; /* 类型,参见HGBASE_IMGTYPE_* */ + HGUInt widthStep; /* 每行的字节数 */ + HGUInt origin; /* 数据排列方式,参见HGBASE_IMGORIGIN_* */ +}HGImageInfo; + +/* 图像感兴趣区域 */ +typedef struct +{ + HGUInt left; + HGUInt top; + HGUInt right; + HGUInt bottom; +}HGImageRoi; + +#pragma pack(pop) + +/* 创建空白的新图像 +* 参数: +* 1) width: in, 新图像宽度 +* 2) height: in, 新图像高度 +* 3) type: in, 新图像类型 +* 4) origin: in, 新图像的数据排列方式 +* 5) image: out,新图像句柄 +* 说明: +* 1)在windows系统上,当type为HGBASE_IMGTYPE_BINARY、HGBASE_IMGTYPE_GRAY、HGBASE_IMGTYPE_BGR或HGBASE_IMGTYPE_BGRA时,新图像内部实际创建DIB位图(有HBITMAP), +* 否则内部分配普通内存(无HBITMAP); 在linux系统上,新图像内部分配普通内存(无HBITMAP) +* 2) 新图像的width=width; 新图像的height=height; 新图像的type=type; 新图像的widthStep为4字节对齐; 新图像的origin=origin +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=96, ydpi=96 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateImage(HGUInt width, HGUInt height, HGUInt type, HGUInt origin, HGImage* image); + +/* 从源数据创建新图像(不分配内存, 也不拷贝数据) +* 参数: +* 1) data: in, 源数据的地址 +* 2) info: in, 源数据的图像信息 +* 3) image: out,新图像句柄 +* 说明: +* 1) 新图像内部不会分配普通像素内存,也不会创建DIB位图(windows系统上, 无HBITMAP),而是直接使用源数据, 在该图像销毁之前需要保证源数据一直有效 +* 2) 新图像的width=info->width; 新图像的height=info->height; 新图像的type=info->type; 新图像的widthStep=info->widthStep; +* 新图像的origin=info->origin +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=96, ydpi=96 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateImageWithData(HGByte* data, const HGImageInfo* info, HGImage* image); + +/* 从源数据创建新图像 +* 参数: +* 1) data: in, 源数据的地址 +* 2) info: in, 源数据的图像信息 +* 3) roi: in, 源数据的感兴趣区域, NULL表示整个图像区域 +* 4) type: in, 新图像的类型, 0表示和源数据一样 +* 5) origin: in, 新图像的数据排列方式, 0表示和源数据一样 +* 6) image: out,新图像句柄 +* 说明: +* 1)在windows系统上,当type为HGBASE_IMGTYPE_BINARY、HGBASE_IMGTYPE_GRAY、HGBASE_IMGTYPE_BGR或HGBASE_IMGTYPE_BGRA时,新图像内部实际创建DIB位图(有HBITMAP), +* 否则内部分配普通内存(无HBITMAP); 在linux系统上,新图像内部分配普通内存(无HBITMAP) +* 2) 新图像的width=roi->right-roi->left; 新图像的height=roi->bottom-roi->top; 新图像的type=type; 新图像的widthStep为4字节对齐; +* 新图像的origin=origin, 如果origin和info->origin不一致,拷贝时像素会进行上下翻转 +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=96, ydpi=96 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateImageFromData(HGByte* data, const HGImageInfo *info, const HGImageRoi *roi, + HGUInt type, HGUInt origin, HGImage* image); + +#if defined(HG_CMP_MSC) + +/* 从DIB位图创建新图像 +* 参数: +* 1) hBmp: in, DIB位图句柄 +* 2) roi: DIB位图的感兴趣区域, NULL表示整个图像区域 +* 3) type: in, 新图像的类型, 0表示自动生成和DIB位图最接近的type +* 4) origin: in, 新图像的数据排列方式, 必须指定 +* 5) image: out,新图像句柄 +* 说明: +* 1)当type为HGBASE_IMGTYPE_BINARY、HGBASE_IMGTYPE_GRAY、HGBASE_IMGTYPE_BGR或HGBASE_IMGTYPE_BGRA时,新图像内部实际创建DIB位图(有HBITMAP), +* 否则内部分配普通内存(无HBITMAP) +* 2) 新图像的width=roi->right-roi->left; 新图像的height=roi->bottom-roi->top; 新图像的type=type; 新图像的widthStep为4字节对齐; +* 新图像的origin=origin +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=hBmp的xDPI, ydpi=hBmp的yDPI +*/ +HGEXPORT HGResult HGAPI HGBase_CreateImageFromHBITMAP(HBITMAP hBmp, const HGImageRoi* roi, + HGUInt type, HGUInt origin, HGImage* image); + +/* 从DIB内存创建新图像 +* 参数: +* 1) hMem: in, DIB内存句柄 +* 2) roi: DIB内存的感兴趣区域, NULL表示整个图像区域 +* 3) type: in, 新图像的类型, 0表示自动生成和DIB内存最接近的type +* 4) origin: in, 新图像的数据排列方式, 必须指定 +* 5) image: out,新图像句柄 +* 说明: +* 1)当type为HGBASE_IMGTYPE_BINARY、HGBASE_IMGTYPE_GRAY、HGBASE_IMGTYPE_BGR或HGBASE_IMGTYPE_BGRA时,新图像内部实际创建DIB位图(有HBITMAP), +* 否则内部分配普通内存(无HBITMAP) +* 2) 新图像的width=roi->right-roi->left; 新图像的height=roi->bottom-roi->top; 新图像的type=type; 新图像的widthStep为4字节对齐; +* 新图像的origin=origin +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=DIB的xDPI, ydpi=DIB的yDPI +*/ +HGEXPORT HGResult HGAPI HGBase_CreateImageFromDIB(HGLOBAL hMem, const HGImageRoi* roi, + HGUInt type, HGUInt origin, HGImage* image); + +#endif /* HG_CMP_MSC */ + +/* 从源图像创建新图像 +* 参数: +* 1) srcImage: in, 源图像 +* 2) type: in, 新图像的类型, 0表示和源图像一样 +* 3) origin: in, 新图像的数据排列方式, 0表示和源图像一样 +* 4) image: out,新图像句柄 +* 说明: +* 1)在windows系统上,当type为HGBASE_IMGTYPE_BINARY、HGBASE_IMGTYPE_GRAY、HGBASE_IMGTYPE_BGR或HGBASE_IMGTYPE_BGRA时,新图像内部实际创建DIB位图(有HBITMAP), +* 否则内部分配普通内存(无HBITMAP); 在linux系统上,新图像内部分配普通内存(无HBITMAP) +* 2) 新图像的width=srcImage->roi.right-srcImage->roi.left; 新图像的height=srcImage->roi.bottom-srcImage->roi.top; +* 新图像的type=type; 新图像的widthStep为4字节对齐; 新图像的origin=origin, 如果origin和srcImage->origin不一致,拷贝时像素会进行上下翻转 +* 3) 新图像的roi为{0, 0, width, height} +* 4) 新图像的xdpi=srcImage->xdpi, ydpi=srcImage->ydpi +*/ +HGEXPORT HGResult HGAPI HGBase_CloneImage(HGImage srcImage, HGUInt type, HGUInt origin, HGImage* image); + +/* 销毁图像 +* 参数: +* 1) image: in, 图像句柄 +* 说明: +* 1) 如果图像内部分配了像素内存, 销毁图像的同时会自动释放 +* 2) 如果图像内部创建了DIB位图(windows上), 销毁图像的同时会自动调用DeleteObject进行销毁 +* 3) 如果图像内存没有分配内存,也没有创建DIB位图,而是直接使用源数据,销毁图像后源数据才可以释放 +*/ +HGEXPORT HGResult HGAPI HGBase_DestroyImage(HGImage image); + +/* 获取图像数据地址 +* 参数: +* 1) image: in, 图像句柄 +* 2) data: out, 数据地址 +* 说明: +* 1) 如果图像内部分配了内存, 返回的是分配的内存地址 +* 2) 如果图像内部创建了DIB位图,返回的是DIB位图像素数据的内存地址 +* 3) 否则,返回的是源数据地址 +*/ +HGEXPORT HGResult HGAPI HGBase_GetImageData(HGImage image, HGByte** data); + +/* 获取图像信息 +* 参数: +* 1) image: in, 图像句柄 +* 2) info: out, 图像信息 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_GetImageInfo(HGImage image, HGImageInfo* info); + +/* 获取图像感兴趣区域 +* 参数: +* 1) image: in, 图像句柄 +* 2) roi: out, 图像感兴趣区域 +* 说明: +* 1) 默认的感兴趣区域整张图, 即left=0,top=0,right=width,bottom=height +* 2) 图像算法模块可以仅处理感兴趣区域 +*/ +HGEXPORT HGResult HGAPI HGBase_GetImageROI(HGImage image, HGImageRoi* roi); + +/* 设置图像感兴趣区域 +* 参数: +* 1) image: in, 图像句柄 +* 2) roi: in, 图像感兴趣区域 +* 说明: +* 1) roi所指定的区域必须是整个图像幅面的子集 +*/ +HGEXPORT HGResult HGAPI HGBase_SetImageROI(HGImage image, const HGImageRoi* roi); + +/* 重置图像感兴趣区域 +* 参数: +* 1) image: in, 图像句柄 +* 说明: +* 1) 默认的感兴趣区域整张图, 即left=0,top=0,right=width,bottom=height +*/ +HGEXPORT HGResult HGAPI HGBase_ResetImageROI(HGImage image); + +/* 获取图像DPI +* 参数: +* 1) image: in, 图像句柄 +* 2) xDpi: out, xdpi +* 3) yDpi: out, ydpi +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_GetImageDpi(HGImage image, HGUInt *xDpi, HGUInt* yDpi); + +/* 设置图像DPI +* 参数: +* 1) image: in, 图像句柄 +* 2) xDpi: in, xdpi +* 3) yDpi: in, ydpi +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_SetImageDpi(HGImage image, HGUInt xDpi, HGUInt yDpi); + +#if defined(HG_CMP_MSC) + +/* 获取图像内部的DIB位图句柄 +* 参数: +* 1) image: in, 图像句柄 +* 2) hBmp: out, DIB位图句柄 +* 说明: +* 1) 该函数只对windows平台有效 +* 2) 返回的HBITMAP不能用DeleteObject销毁 +*/ +HGEXPORT HGResult HGAPI HGBase_GetHBITMAPOfImage(HGImage image, HBITMAP *hBmp); + +/* 创建DIB位图 +* 参数: +* 1) image: in, 图像句柄 +* 2) hBmp: out, DIB位图句柄 +* 说明: +* 1) 该函数只对windows平台有效 +* 2) 返回的hBmp必须用DeleteObject销毁 +* 3) 操作的只是图像的ROI区域 +* 4) HGBASE_IMGTYPE_RGB会自动转为BGR排列, HGBASE_IMGTYPE_RGBA会自动转为BGRA排列 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateHBITMAPFromImage(HGImage image, HBITMAP* hBmp); + +/* 创建DIB内存 +* 参数: +* 1) image: in, 图像句柄 +* 2) hMem: out, DIB内存句柄 +* 说明: +* 1) 该函数只对windows平台有效 +* 2) 返回的hMem必须用GlobalFree销毁 +* 3) 操作的只是图像的ROI区域 +* 4) HGBASE_IMGTYPE_RGB会自动转为BGR排列, HGBASE_IMGTYPE_RGBA会自动转为BGRA排列 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateDIBFromImage(HGImage image, HGLOBAL* hMem); + +#endif /* HG_CMP_MSC */ + +/* 图像左右镜像 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageMirror(HGImage image, HGImage destImage); + +/* 图像上下镜像 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageFlip(HGImage image, HGImage destImage); + +/* 图像左转 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须宽高互反 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage不能是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageRotateLeft(HGImage image, HGImage destImage); + +/* 图像右转 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须宽高互反 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage不能是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageRotateRight(HGImage image, HGImage destImage); + +/* 图像左转后再左右镜像 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须宽高互反 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage不能是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageRotateLeftMirror(HGImage image, HGImage destImage); + +/* 图像右转后再左右镜像 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须宽高互反 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage不能是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageRotateRightMirror(HGImage image, HGImage destImage); + +/* 图像旋转180度 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageRotate180(HGImage image, HGImage destImage); + +/* 图像灰度化 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ImageGrayscale(HGImage image, HGImage destImage); + +/* 图像反色 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_ReverseImage(HGImage image, HGImage destImage); + +/* 拷贝图像 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 说明: +* 1) 操作的只是图像的ROI区域, 源图像和目标图像的ROI大小必须一样 +* 2) 拷贝的时候会自动处理type不一致的情况 +* 3) 拷贝的时候自动处理origin不一致的情况 +* 4) image和destImage不能是同一个图像句柄 +*/ +HGEXPORT HGResult HGAPI HGBase_CopyImage(HGImage image, HGImage destImage); + +#endif /* __HGIMAGE_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGInc.h b/app/sdk/include/base/HGInc.h new file mode 100644 index 0000000..f8ee028 --- /dev/null +++ b/app/sdk/include/base/HGInc.h @@ -0,0 +1,39 @@ +#ifndef __HGINC_H__ +#define __HGINC_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(HG_CMP_MSC) +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#endif /* __HGINC_H__ */ diff --git a/app/sdk/include/base/HGInfo.h b/app/sdk/include/base/HGInfo.h new file mode 100644 index 0000000..7526647 --- /dev/null +++ b/app/sdk/include/base/HGInfo.h @@ -0,0 +1,36 @@ +#ifndef __HGINFO_H__ +#define __HGINFO_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* 致命错误 */ +#define HGBASE_INFOTYPE_FATAL 1L +/* 一般错误 */ +#define HGBASE_INFOTYPE_ERROR 2L +/* 警告 */ +#define HGBASE_INFOTYPE_WARNING 4L +/* 一般描述信息 */ +#define HGBASE_INFOTYPE_DESC 8L +/* 调试信息 */ +#define HGBASE_INFOTYPE_DEBUG 16L + +/* 启用日志/控制台信息 +*/ +HGEXPORT HGResult HGAPI HGBase_EnableInfo(); + +/* 禁用日志/控制台信息 +*/ +HGEXPORT HGResult HGAPI HGBase_DisableInfo(); + +/* 写日志/控制台信息 +* 参数: +* 1) type: in, 信息类型, 参见HGBASE_INFOTYPE_* +* 2) format: in, 信息格式 +* 说明: +* 1) 信息的完整输出行: [日期-时间] [进程号/线程号] [信息类型] [信息] +* 2) 信息的实际输出行取决于config.ini的配置 +*/ +HGEXPORT HGResult HGAPIV HGBase_WriteInfo(HGUInt type, const HGChar* format, ...); + +#endif /* __HGINFO_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGIni.h b/app/sdk/include/base/HGIni.h new file mode 100644 index 0000000..82cc2c8 --- /dev/null +++ b/app/sdk/include/base/HGIni.h @@ -0,0 +1,27 @@ +#ifndef __HGINI_H__ +#define __HGINI_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* 设置ini文件的值 +*/ +HGEXPORT HGResult HGAPI HGBase_SetProfileInt(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, HGInt value); + +/* 设置ini文件的值 +*/ +HGEXPORT HGResult HGAPI HGBase_SetProfileString(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, const HGChar* value); + +/* 获取ini文件的值 +*/ +HGEXPORT HGResult HGAPI HGBase_GetProfileInt(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, HGInt def, HGInt* value); + +/* 获取ini文件的值 +*/ +HGEXPORT HGResult HGAPI HGBase_GetProfileString(const HGChar* fileName, const HGChar* appName, + const HGChar* keyName, const HGChar* def, HGChar* value, HGUInt maxLen); + +#endif /* __HGINI_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGLock.h b/app/sdk/include/base/HGLock.h new file mode 100644 index 0000000..128d03b --- /dev/null +++ b/app/sdk/include/base/HGLock.h @@ -0,0 +1,37 @@ +#ifndef __HGLOCK_H__ +#define __HGLOCK_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGLock); + +/* 创建互斥锁 +* 参数: +* 1) lock: out, 互斥锁句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_CreateLock(HGLock* lock); + +/* 销毁互斥锁 +* 参数: +* 1) lock: in, 互斥锁句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_DestroyLock(HGLock lock); + +/* 加锁 +* 参数: +* 1) lock: in, 互斥锁句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_EnterLock(HGLock lock); + +/* 解锁 +* 参数: +* 1) lock: in, 互斥锁句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_LeaveLock(HGLock lock); + +#endif /* __HGLOCK_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGLog.h b/app/sdk/include/base/HGLog.h new file mode 100644 index 0000000..fa18a71 --- /dev/null +++ b/app/sdk/include/base/HGLog.h @@ -0,0 +1,42 @@ +#ifndef __HGLOG_H__ +#define __HGLOG_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGLog); + +/* 开启日志 +* 参数: +* 1) fileName: in, 文件名 +* 2) log: out, 日志句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_OpenLog(const HGChar* fileName, HGLog* log); + +/* 关闭日志 +* 参数: +* 1) log: in, 日志句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_CloseLog(HGLog log); + +/* 获取日志文件大小 +* 参数: +* 1) log: in, 日志句柄 +* 2) size: out, 日志文件大小 +* 说明: +* 1) 每次写入日志信息后,可以用该函数检查日志文件的大小,当日志文件足够大时,可以关闭该日志句柄,在新的日志文件上重新打开 +*/ +HGEXPORT HGResult HGAPI HGBase_GetLogFileSize(HGLog log, HGLonglong* size); + +/* 写日志信息 +* 参数: +* 1) log: in, 日志句柄 +* 2) info: in, 信息, 一次一行, info无需加换行符 +* 说明: +* 1) 该函数不是线程安全的, 在不同进程或不同线程调用的时候, 需要加锁 +*/ +HGEXPORT HGResult HGAPI HGBase_WriteLog(HGLog log, const HGChar* info); + +#endif /* __HGLOG_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGMd5.h b/app/sdk/include/base/HGMd5.h new file mode 100644 index 0000000..e9406c2 --- /dev/null +++ b/app/sdk/include/base/HGMd5.h @@ -0,0 +1,16 @@ +#ifndef __HGMD5_H__ +#define __HGMD5_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* 生成MD5值 +* 参数: +* 1) data: in, 数据地址 +* 2) size: in, 数据长度 +* 3) md5: out, md5值, 必须至少分配16字节 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_MakeMd5(const HGByte* data, HGUInt size, HGByte* md5); + +#endif /* __HGMD5_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGMsgPump.h b/app/sdk/include/base/HGMsgPump.h new file mode 100644 index 0000000..5ab886c --- /dev/null +++ b/app/sdk/include/base/HGMsgPump.h @@ -0,0 +1,33 @@ +#ifndef __HGMSGPUMP_H__ +#define __HGMSGPUMP_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGMsgPump); + +#pragma pack(push) +#pragma pack(4) + +/* 消息结构体, 可以自定义 */ +typedef struct +{ + HGUInt id; /* 消息ID, 不能为0 */ + HGPointer data; /* 携带的数据 */ +}HGMsg; + +#pragma pack(pop) + +typedef void (HGAPI *HGMsgPumpFunc)(HGMsgPump msgPump, const HGMsg* msg, HGPointer param); + +HGEXPORT HGResult HGAPI HGBase_CreateMsgPump(HGMsgPump *msgPump); + +HGEXPORT HGResult HGAPI HGBase_DestroyMsgPump(HGMsgPump msgPump); + +HGEXPORT HGResult HGAPI HGBase_RunMsgPump(HGMsgPump msgPump, HGMsgPumpFunc func, HGPointer param); + +HGEXPORT HGResult HGAPI HGBase_PostPumpMessage(HGMsgPump msgPump, const HGMsg *msg); + +HGEXPORT HGResult HGAPI HGBase_ExitMsgPump(HGMsgPump msgPump); + +#endif /* __HGMSGPUMP_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGNamedPipe.h b/app/sdk/include/base/HGNamedPipe.h new file mode 100644 index 0000000..2467203 --- /dev/null +++ b/app/sdk/include/base/HGNamedPipe.h @@ -0,0 +1,30 @@ +#ifndef __HGNAMEDPIPE_H__ +#define __HGNAMEDPIPE_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGNamedPipeServer); +HG_DECLARE_HANDLE(HGNamedPipeClient); + +HGEXPORT HGResult HGAPI HGBase_OpenNamedPipeServer(const HGChar* pipeName, HGNamedPipeServer *server); + +HGEXPORT HGResult HGAPI HGBase_CloseNamedPipeServer(HGNamedPipeServer server); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeServerWrite(HGNamedPipeServer server, const HGByte* data, HGUInt size, HGUInt* writeSize); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeServerRead(HGNamedPipeServer server, HGByte* data, HGUInt size, HGUInt* readSize); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeServerStop(HGNamedPipeServer server); + +HGEXPORT HGResult HGAPI HGBase_OpenNamedPipeClient(const HGChar* pipeName, HGNamedPipeClient* client); + +HGEXPORT HGResult HGAPI HGBase_CloseNamedPipeClient(HGNamedPipeClient client); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeClientWrite(HGNamedPipeClient client, const HGByte* data, HGUInt size, HGUInt* writeSize); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeClientRead(HGNamedPipeClient client, HGByte* data, HGUInt size, HGUInt* readSize); + +HGEXPORT HGResult HGAPI HGBase_NamedPipeClientStop(HGNamedPipeClient client); + +#endif /* __HGNAMEDPIPE_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGThread.h b/app/sdk/include/base/HGThread.h new file mode 100644 index 0000000..4c688fc --- /dev/null +++ b/app/sdk/include/base/HGThread.h @@ -0,0 +1,34 @@ +#ifndef __HGTHREAD_H__ +#define __HGTHREAD_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +HG_DECLARE_HANDLE(HGThread); + +/* 线程回调函数 +* 参数: +* 1) thread: in, 线程句柄 +* 2) param: in, 回调参数 +* 说明: +*/ +typedef void (HGAPI *HGThreadFunc)(HGThread thread, HGPointer param); + +/* 开启线程 +* 参数: +* 1) func: in, 线程回调函数 +* 2) param: in, 回调参数 +* 3) thread: out, 线程句柄 +* 说明: +*/ +HGEXPORT HGResult HGAPI HGBase_OpenThread(HGThreadFunc func, HGPointer param, HGThread *thread); + +/* 关闭线程 +* 参数: +* 1) thread: in, 线程句柄 +* 说明: +* 1) 该函数会等待线程正常结束, 如果线程阻塞, 该函数也会阻塞 +*/ +HGEXPORT HGResult HGAPI HGBase_CloseThread(HGThread thread); + +#endif /* __HGTHREAD_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGTime.h b/app/sdk/include/base/HGTime.h new file mode 100644 index 0000000..41fb8e4 --- /dev/null +++ b/app/sdk/include/base/HGTime.h @@ -0,0 +1,26 @@ +#ifndef __HGTIME_H__ +#define __HGTIME_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUShort year; + HGUShort month; + HGUShort day; + HGUShort dayOfWeek; /* 0Ϊ, 1-6ʾһ */ + HGUShort hour; + HGUShort minute; + HGUShort second; + HGUShort milliseconds; +}HGTimeInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGBase_GetLocalTime(HGTimeInfo *timeInfo); + +#endif /* __HGTIME_H__ */ \ No newline at end of file diff --git a/app/sdk/include/base/HGUtility.h b/app/sdk/include/base/HGUtility.h new file mode 100644 index 0000000..aa388e3 --- /dev/null +++ b/app/sdk/include/base/HGUtility.h @@ -0,0 +1,80 @@ +#ifndef __HGUTILITY_H__ +#define __HGUTILITY_H__ + +#include "HGDef.h" +#include "HGBaseErr.h" + +/* 获取系统临时文件目录 +*/ +HGEXPORT HGResult HGAPI HGBase_GetTmpPath(HGChar* path, HGUInt maxLen); + +/* 获取进程的当前工作目录 +*/ +HGEXPORT HGResult HGAPI HGBase_GetCurrentDir(HGChar* dir, HGUInt maxLen); + +/* 设置进程的当前工作目录 +*/ +HGEXPORT HGResult HGAPI HGBase_SetCurrentDir(const HGChar* dir); + +/* 创建目录 +* 该函数可以创建多级目录 +*/ +HGEXPORT HGResult HGAPI HGBase_CreateDir(const HGChar* dir); + +/* 删除目录 +* 该函数只能用于删除空目录 +*/ +HGEXPORT HGResult HGAPI HGBase_DeleteDir(const HGChar* dir); + +/* 删除文件 +*/ +HGEXPORT HGResult HGAPI HGBase_DeleteFile(const HGChar* fileName); + +/* 获取模块名称 +*/ +HGEXPORT HGResult HGAPI HGBase_GetModuleName(HGPointer addr, HGChar* name, HGUInt maxLen); + +/* 获取UUID +*/ +HGEXPORT HGResult HGAPI HGBase_GetUuid(HGChar* uuid, HGUInt maxLen); + +/* 获取临时文件名 +*/ +HGEXPORT HGResult HGAPI HGBase_GetTmpFileName(const HGChar *suffix, HGChar* fileName, HGUInt maxLen); + +/* 获取配置文件路径 +*/ +HGEXPORT HGResult HGAPI HGBase_GetConfigPath(HGChar* configPath, HGUInt maxLen); + +/* 获取日志文件路径 +*/ +HGEXPORT HGResult HGAPI HGBase_GetLogFilePath(HGChar* logFilePath, HGUInt maxLen); + +/* 获取文档路径 +*/ +HGEXPORT HGResult HGAPI HGBase_GetDocumentsPath(HGChar* documentsPath, HGUInt maxLen); + +/* 获取进程名 +*/ +HGEXPORT HGResult HGAPI HGBase_GetProcessName(HGChar* name, HGUInt maxLen); + +/* 通过文件全路径获取路径 +*/ +HGEXPORT HGResult HGAPI HGBase_GetFilePath(const HGChar* fileName, HGChar* path, HGUInt maxLen); + +/* 通过文件全路径获取文件名 +*/ +HGEXPORT HGResult HGAPI HGBase_GetFileName(const HGChar* fileName, HGChar* name, HGUInt maxLen); + +/* 通过文件名获取文件前缀 +*/ +HGEXPORT HGResult HGAPI HGBase_GetFilePrefix(const HGChar* fileName, HGChar* prefix, HGUInt maxLen); + +/* 通过文件名获取文件后缀 +*/ +HGEXPORT HGResult HGAPI HGBase_GetFileSuffix(const HGChar *fileName, HGChar* suffix, HGUInt maxLen); + +/* 将文件名标准化 */ +HGEXPORT HGResult HGAPI HGBase_StandardiseFileName(const HGChar* fileName, HGChar *result, HGUInt maxLen); + +#endif /* __HGUTILITY_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgfmt/HGBmp.h b/app/sdk/include/imgfmt/HGBmp.h new file mode 100644 index 0000000..ec59eb3 --- /dev/null +++ b/app/sdk/include/imgfmt/HGBmp.h @@ -0,0 +1,69 @@ +#ifndef __HGBMP_H__ +#define __HGBMP_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +/* 压缩方式 */ +#define HGIMGFMT_BMPENCODING_RGB 0L +#define HGIMGFMT_BMPENCODING_RLE8 1L +#define HGIMGFMT_BMPENCODING_RLE4 2L +#define HGIMGFMT_BMPENCODING_BITFIELDS 3L + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 宽 */ + HGUInt height; /* 高 */ + HGUShort bitCount; /* 每像素比特数 */ + HGUInt compression; /* 压缩方式, 见HGIMGFMT_BMPENCODING_ */ + HGUInt xPelsPerMeter; /* 每米的像素数x */ + HGUInt yPelsPerMeter; /* 每米的像素数y */ +}HGBmpLoadInfo; + +typedef struct +{ + HGUInt xPelsPerMeter; /* 每米的像素数x */ + HGUInt yPelsPerMeter; /* 每米的像素数y */ +}HGBmpSaveInfo; + +#pragma pack(pop) + +/* 检查文件是否是BMP图像 +* 参数: +* 1) fileName: in, 文件名, windows系统上是GBK编码, linux系统上是UTF8编码 +* 2) isBmp: out, 是否是BMP图像 +* 说明: +* 1) 该函数会打开文件判断文件头,而不是判断文件名后缀 +*/ +HGEXPORT HGResult HGAPI HGImgFmt_CheckBmpFile(const HGChar* fileName, HGBool* isBmp); + +/* 加载BMP图像 +* 参数: +* 1) fileName: in, 文件名, windows系统上是GBK编码, linux系统上是UTF8编码 +* 2) info: out, BMP图像加载信息, 如果不需要该信息可传NULL +* 3) imgType: in, 要生成的图像类型, 参见HGBASE_IMGTYPE_*, 传0表示自动获取 +* 4) imgOrigin: in, 要生成的图像数据排列方式, 参见HGBASE_IMGORIGIN_*, 传0表示自动获取 +* 5) image: out, 要生成的图像句柄 +* 说明: +* 1) 生成的图像不使用时需要调用HGBase_DestroyImage销毁 +*/ +HGEXPORT HGResult HGAPI HGImgFmt_LoadBmpImage(const HGChar* fileName, HGBmpLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +/* 保存BMP图像 +* 参数: +* 1) image: in, 要保存的图像句柄 +* 2) info: in, BMP图像保存信息, 如果没有则传NULL +* 3) fileName: in, 文件名, windows系统上是GBK编码, linux系统上是UTF8编码 +* 说明: +* 1) 忽略fileName的文件扩展名 +* 2) 如果info不为NULL, 保存的DPI使用info指定的; 否则使用image自带的 +*/ +HGEXPORT HGResult HGAPI HGImgFmt_SaveBmpImage(HGImage image, const HGBmpSaveInfo* info, const HGChar* fileName); + +#endif /* __HGBMP_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgfmt/HGGif.h b/app/sdk/include/imgfmt/HGGif.h new file mode 100644 index 0000000..b0ae138 --- /dev/null +++ b/app/sdk/include/imgfmt/HGGif.h @@ -0,0 +1,55 @@ +#ifndef __HGGIF_H__ +#define __HGGIF_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +HG_DECLARE_HANDLE(HGGifReader); +HG_DECLARE_HANDLE(HGGifWriter); + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUInt colorResolution; /* 位深 */ + HGUInt imageCount; /* 图像数量 */ +}HGGifLoadInfo; + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ +}HGGifSaveInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckGifFile(const HGChar* fileName, HGBool* isGif); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenGifReader(const HGChar* fileName, HGGifLoadInfo* info, HGGifReader* reader); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseGifReader(HGGifReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_RetrieveImageFromGifReader(HGGifReader reader, HGUInt *index, HGUInt *interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromGifReader(HGGifReader reader, HGUInt index, HGUInt* interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadGifImage(const HGChar* fileName, HGGifLoadInfo* info, HGUInt* interval, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenGifWriter(const HGChar* fileName, const HGGifSaveInfo* info, HGGifWriter* writer); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseGifWriter(HGGifWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveImageToGifWriter(HGGifWriter writer, HGUInt interval, HGColor bkColor, HGImage image); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveGifImage(HGImage image, const HGGifSaveInfo* info, + HGUInt interval, HGColor bkColor, const HGChar* fileName); + +#endif /* __HGGIF_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgfmt/HGImgFmt.h b/app/sdk/include/imgfmt/HGImgFmt.h new file mode 100644 index 0000000..133b848 --- /dev/null +++ b/app/sdk/include/imgfmt/HGImgFmt.h @@ -0,0 +1,77 @@ +#ifndef __HGIMGFMT_H__ +#define __HGIMGFMT_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" +#include "HGTiff.h" + +HG_DECLARE_HANDLE(HGImgFmtReader); +HG_DECLARE_HANDLE(HGImgFmtWriter); + +/* JPEG */ +#define HGIMGFMT_TYPE_JPEG 1L +/* BMP */ +#define HGIMGFMT_TYPE_BMP 2L +/* PNG */ +#define HGIMGFMT_TYPE_PNG 3L +/* TIFF */ +#define HGIMGFMT_TYPE_TIFF 4L +/* PDF */ +#define HGIMGFMT_TYPE_PDF 5L +/* OFD */ +#define HGIMGFMT_TYPE_OFD 6L +/* GIF */ +#define HGIMGFMT_TYPE_GIF 7L +/* PNM */ +#define HGIMGFMT_TYPE_PNM 8L + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUInt bpp; /* 每像素比特数 */ + HGUInt xDpi; /* x-DPI */ + HGUInt yDpi; /* y-DPI */ +}HGImgFmtLoadInfo; + +typedef struct +{ + HGUInt jpegQuality; /* jpeg质量 */ + HGUInt tiffCompression; /* tiff压缩方式, 见HGIMGFMT_TIFFCOMP_* */ + HGUInt tiffJpegQuality; /* tiff-jpeg质量 */ +}HGImgFmtSaveInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_GetImgFmtType(const HGChar* fileName, HGUInt* fmtType); + +HGEXPORT HGResult HGAPI HGImgFmt_GetImgFmtTypeFromFileName(const HGChar* fileName, HGUInt* fmtType); + +HGEXPORT HGResult HGAPI HGImgFmt_IsMultiImgFmtType(HGUInt fmtType, HGBool *isMulti); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImage(const HGChar *fileName, HGUInt fmtType, HGImgFmtLoadInfo *info, + HGUInt imgType, HGUInt imgOrigin, HGImage *image); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveImage(HGImage image, HGUInt fmtType, const HGImgFmtSaveInfo *info, const HGChar *fileName); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenImageReader(const HGChar *fileName, HGUInt fmtType, HGImgFmtReader *reader); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseImageReader(HGImgFmtReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_GetImagePageCount(HGImgFmtReader reader, HGUInt *count); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromReader(HGImgFmtReader reader, HGUInt index, HGImgFmtLoadInfo *info, + HGUInt imgType, HGUInt imgOrigin, HGImage *image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenImageWriter(const HGChar *fileName, HGUInt fmtType, HGImgFmtWriter *writer); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseImageWriter(HGImgFmtWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveImageToWriter(HGImgFmtWriter writer, HGImage image, const HGImgFmtSaveInfo *info); + +#endif /* __HGIMGFMT_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgfmt/HGImgFmtErr.h b/app/sdk/include/imgfmt/HGImgFmtErr.h new file mode 100644 index 0000000..c334856 --- /dev/null +++ b/app/sdk/include/imgfmt/HGImgFmtErr.h @@ -0,0 +1,7 @@ +#ifndef __HGIMGFMTERR_H__ +#define __HGIMGFMTERR_H__ + +/* 一般错误 */ +#define HGIMGFMT_ERR_FAIL 0x00002001L + +#endif /* __HGIMGFMTERR_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgfmt/HGJpeg.h b/app/sdk/include/imgfmt/HGJpeg.h new file mode 100644 index 0000000..fdf9a94 --- /dev/null +++ b/app/sdk/include/imgfmt/HGJpeg.h @@ -0,0 +1,55 @@ +#ifndef __HGJPEG_H__ +#define __HGJPEG_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" +#include "../base/HGBuffer.h" + +/* 颜色空间 */ +#define HGIMGFMT_JPEGCLRSPACE_UNKNOWN 0L +#define HGIMGFMT_JPEGCLRSPACE_GRAYSCALE 1L +#define HGIMGFMT_JPEGCLRSPACE_RGB 2L + +/* 分辨率单位 */ +#define HGIMGFMT_JPEGDENUNIT_INCH 1L /* 英寸 */ +#define HGIMGFMT_JPEGDENUNIT_CENTIMETER 2L /* 厘米 */ + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUInt numComponents; /* 颜色数量 */ + HGUInt colorSpace; /* 颜色空间, 见HGIMGFMT_JPEGCLRSPACE_* */ + HGByte densityUnit; /* 分辨率单位, 见HGIMGFMT_JPEGDENUNIT_* */ + HGUShort xDensity; /* 分辨率x值 */ + HGUShort yDensity; /* 分辨率y值 */ +}HGJpegLoadInfo; + +typedef struct +{ + HGUInt quality; /* 压缩质量, 0-100 */ + HGByte densityUnit; /* 分辨率单位, 见HGIMGFMT_JPEGDENUNIT_* */ + HGUShort xDensity; /* 分辨率x值 */ + HGUShort yDensity; /* 分辨率y值 */ +}HGJpegSaveInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckJpegFile(const HGChar* fileName, HGBool *isJpeg); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadJpegImage(const HGChar* fileName, HGJpegLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadJpegImageFromBuffer(HGBuffer buffer, HGJpegLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveJpegImage(HGImage image, const HGJpegSaveInfo* info, const HGChar* fileName); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveJpegImageToBuffer(HGImage image, const HGJpegSaveInfo* info, HGBuffer *buffer); + +#endif /* __HGJPEG_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgfmt/HGOfd.h b/app/sdk/include/imgfmt/HGOfd.h new file mode 100644 index 0000000..0821508 --- /dev/null +++ b/app/sdk/include/imgfmt/HGOfd.h @@ -0,0 +1,48 @@ +#ifndef __HGOFD_H__ +#define __HGOFD_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" +#include "HGJpeg.h" + +HG_DECLARE_HANDLE(HGOfdReader); +HG_DECLARE_HANDLE(HGOfdImageWriter); + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; + HGUInt height; + HGUInt bpp; +}HGOfdPageInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckOfdFile(const HGChar* fileName, HGBool* isOfd); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenOfdReader(const HGChar* fileName, HGOfdReader* reader); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseOfdReader(HGOfdReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_GetOfdPageCount(HGOfdReader reader, HGUInt* count); + +HGEXPORT HGResult HGAPI HGImgFmt_GetOfdPageInfo(HGOfdReader reader, HGUInt page, HGOfdPageInfo* info); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromOfdReader(HGOfdReader reader, HGUInt page, HGFloat xScale, HGFloat yScale, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadOfdImage(const HGChar* fileName, HGOfdPageInfo* info, HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenOfdImageWriter(const HGChar* fileName, HGOfdImageWriter* writer); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseOfdImageWriter(HGOfdImageWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveJpegImageToOfdImageWriter(HGOfdImageWriter writer, HGImage image, const HGJpegSaveInfo* info); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveOfdJpegImage(HGImage image, const HGJpegSaveInfo* info, const HGChar* fileName); + +#endif /* __HGOFD_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgfmt/HGPdf.h b/app/sdk/include/imgfmt/HGPdf.h new file mode 100644 index 0000000..7dac61b --- /dev/null +++ b/app/sdk/include/imgfmt/HGPdf.h @@ -0,0 +1,48 @@ +#ifndef __HGPDF_H__ +#define __HGPDF_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" +#include "HGJpeg.h" + +HG_DECLARE_HANDLE(HGPdfReader); +HG_DECLARE_HANDLE(HGPdfImageWriter); + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; + HGUInt height; + HGUInt bpp; +}HGPdfPageInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckPdfFile(const HGChar* fileName, HGBool* isPdf); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenPdfReader(const HGChar* fileName, HGPdfReader* reader); + +HGEXPORT HGResult HGAPI HGImgFmt_ClosePdfReader(HGPdfReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_GetPdfPageCount(HGPdfReader reader, HGUInt* count); + +HGEXPORT HGResult HGAPI HGImgFmt_GetPdfPageInfo(HGPdfReader reader, HGUInt page, HGPdfPageInfo *info); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromPdfReader(HGPdfReader reader, HGUInt page, HGFloat xScale, HGFloat yScale, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadPdfImage(const HGChar* fileName, HGPdfPageInfo *info, HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenPdfImageWriter(const HGChar* fileName, HGPdfImageWriter* writer); + +HGEXPORT HGResult HGAPI HGImgFmt_ClosePdfImageWriter(HGPdfImageWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveJpegImageToPdfImageWriter(HGPdfImageWriter writer, HGImage image, const HGJpegSaveInfo* info); + +HGEXPORT HGResult HGAPI HGImgFmt_SavePdfJpegImage(HGImage image, const HGJpegSaveInfo* info, const HGChar* fileName); + +#endif /* __HGPDF_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgfmt/HGPng.h b/app/sdk/include/imgfmt/HGPng.h new file mode 100644 index 0000000..c040913 --- /dev/null +++ b/app/sdk/include/imgfmt/HGPng.h @@ -0,0 +1,65 @@ +#ifndef __HGPNG_H__ +#define __HGPNG_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +/* */ +#define HGIMGFMT_PNGCLRTYPE_GRAY 0L +#define HGIMGFMT_PNGCLRTYPE_PALETTE (1L | 2L) +#define HGIMGFMT_PNGCLRTYPE_RGB 2L +#define HGIMGFMT_PNGCLRTYPE_RGB_ALPHA (2L | 4L) +#define HGIMGFMT_PNGCLRTYPE_GRAY_ALPHA 4L + +/* */ +#define HGIMGFMT_PNGFILTERTYPE_BASE 0L +/* */ +#define HGIMGFMT_PNGINTERLACE_NONE 0L +#define HGIMGFMT_PNGINTERLACE_ADAM7 1L +#define HGIMGFMT_PNGINTERLACE_LAST 2L +/* */ +#define HGIMGFMT_PNGCOMPTYPE_BASE 0L + +/* 分辨率单位 */ +#define HGIMGFMT_PNGPHYSUNIT_UNKNOWN 0L +#define HGIMGFMT_PNGPHYSUNIT_METER 1L +#define HGIMGFMT_PNGPHYSUNIT_LAST 2L + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGByte bitDepth; /* 每通道的比特数 */ + HGByte colorType; /* 色彩类型, 见HGIMGFMT_PNGCLRTYPE_* */ + HGByte channels; /* 通道数 */ + HGByte filterType; /* 见HGIMGFMT_PNGFILTERTYPE_* */ + HGByte InterlaceType; /* 见HGIMGFMT_PNGINTERLACE_* */ + HGByte compressionType; /* 见HGIMGFMT_PNGCOMPTYPE_* */ + HGByte pixelDepth; /* 每像素的比特数 */ + HGByte physUnitType; /* 分辨率单位, 见HGIMGFMT_PNGPHYSUNIT_* */ + HGUInt xPixelsPerUnit; /* 分辨率x */ + HGUInt yPixelsPerUnit; /* 分辨率y */ +}HGPngLoadInfo; + +typedef struct +{ + HGByte physUnitType; /* 分辨率单位, 见HGIMGFMT_PNGPHYSUNIT_* */ + HGUInt xPixelsPerUnit; /* 分辨率x */ + HGUInt yPixelsPerUnit; /* 分辨率y */ +}HGPngSaveInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckPngFile(const HGChar* fileName, HGBool* isPng); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadPngImage(const HGChar* fileName, HGPngLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_SavePngImage(HGImage image, const HGPngSaveInfo* info, const HGChar* fileName); + +#endif /* __HGPNG_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgfmt/HGPnm.h b/app/sdk/include/imgfmt/HGPnm.h new file mode 100644 index 0000000..ee393e6 --- /dev/null +++ b/app/sdk/include/imgfmt/HGPnm.h @@ -0,0 +1,43 @@ +#ifndef __HGPNM_H__ +#define __HGPNM_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +#define HGIMGFMT_PNMTYPE_BINARY_ASCII 1L +#define HGIMGFMT_PNMTYPE_BINARY_BINARY 2L +#define HGIMGFMT_PNMTYPE_GRAY_ASCII 3L +#define HGIMGFMT_PNMTYPE_GRAY_BINARY 4L +#define HGIMGFMT_PNMTYPE_RGB_ASCII 5L +#define HGIMGFMT_PNMTYPE_RGB_BINARY 6L + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUInt type; /* 类型 */ +}HGPnmLoadInfo; + +typedef struct +{ + HGUInt type; /* 类型 */ +}HGPnmSaveInfo; + +#pragma pack(pop) + + +HGEXPORT HGResult HGAPI HGImgFmt_CheckPnmFile(const HGChar* fileName, HGBool* isPnm); + +HGEXPORT HGResult HGAPI HGImgFmt_GetPnmTypeFromFileName(const HGChar* fileName, HGUInt* pnmType); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadPnmImage(const HGChar* fileName, HGPnmLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_SavePnmImage(HGImage image, const HGPnmSaveInfo* info, const HGChar* fileName); + +#endif // __HGPNM_H__ diff --git a/app/sdk/include/imgfmt/HGTiff.h b/app/sdk/include/imgfmt/HGTiff.h new file mode 100644 index 0000000..324a19e --- /dev/null +++ b/app/sdk/include/imgfmt/HGTiff.h @@ -0,0 +1,71 @@ +#ifndef __HGTIFF_H__ +#define __HGTIFF_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgFmtErr.h" +#include "../base/HGImage.h" + +HG_DECLARE_HANDLE(HGTiffReader); +HG_DECLARE_HANDLE(HGTiffWriter); + +/* 压缩方式 */ +#define HGIMGFMT_TIFFCOMP_NONE 1L +#define HGIMGFMT_TIFFCOMP_CCITTFAX4 4L +#define HGIMGFMT_TIFFCOMP_LZW 5L +#define HGIMGFMT_TIFFCOMP_JPEG 7L + +/* 分辨率单位 */ +#define HGIMGFMT_TIFFRESUNIT_NONE 1L +#define HGIMGFMT_TIFFRESUNIT_INCH 2L /* 英寸 */ +#define HGIMGFMT_TIFFRESUNIT_CENTIMETER 3L /* 厘米 */ + +#pragma pack(push) +#pragma pack(4) + +typedef struct +{ + HGUInt width; /* 图像宽 */ + HGUInt height; /* 图像高 */ + HGUShort bitsPerSample; /* 每个采样的比特数 */ + HGUShort samplesPerPixel; /* 每个像素的采样数 */ + HGUShort compression; /* 压缩方式, 见HGIMGFMT_TIFFCOMP_* */ + HGUShort resolutionUnit; /* 分辨率单位, 见HGIMGFMT_TIFFRESUNIT_* */ + HGFloat xResolution; /* 分辨率x值 */ + HGFloat yResolution; /* 分辨率y值 */ +}HGTiffLoadInfo; + +typedef struct +{ + HGUInt compression; /* 压缩方式, 见HGIMGFMT_TIFFCOMP_* */ + HGUInt jpegQuality; /* jpeg压缩质量, 0-100 */ + HGUShort resolutionUnit; /* 分辨率单位, 见HGIMGFMT_TIFFRESUNIT_* */ + HGFloat xResolution; /* 分辨率x值 */ + HGFloat yResolution; /* 分辨率y值 */ +}HGTiffSaveInfo; + +#pragma pack(pop) + +HGEXPORT HGResult HGAPI HGImgFmt_CheckTiffFile(const HGChar* fileName, HGBool* isTiff); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenTiffReader(const HGChar* fileName, HGTiffReader* reader); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseTiffReader(HGTiffReader reader); + +HGEXPORT HGResult HGAPI HGImgFmt_GetTiffPageCount(HGTiffReader reader, HGUInt* count); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadImageFromTiffReader(HGTiffReader reader, HGUInt index, HGTiffLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_LoadTiffImage(const HGChar* fileName, HGTiffLoadInfo* info, + HGUInt imgType, HGUInt imgOrigin, HGImage* image); + +HGEXPORT HGResult HGAPI HGImgFmt_OpenTiffWriter(const HGChar* fileName, HGTiffWriter* writer); + +HGEXPORT HGResult HGAPI HGImgFmt_CloseTiffWriter(HGTiffWriter writer); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveImageToTiffWriter(HGTiffWriter writer, HGImage image, const HGTiffSaveInfo* info); + +HGEXPORT HGResult HGAPI HGImgFmt_SaveTiffImage(HGImage image, const HGTiffSaveInfo* info, const HGChar* fileName); + +#endif /* __HGTIFF_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgproc/HGImgProc.h b/app/sdk/include/imgproc/HGImgProc.h new file mode 100644 index 0000000..8844759 --- /dev/null +++ b/app/sdk/include/imgproc/HGImgProc.h @@ -0,0 +1,205 @@ +#ifndef __HGIMGPROC_H__ +#define __HGIMGPROC_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgProcErr.h" +#include "../base/HGImage.h" + +/* 最近邻插值 */ +#define HGIMGPROC_INTERPOTYPE_NN 1L +/* 双线性插值 */ +#define HGIMGPROC_INTERPOTYPE_LINEAR 2L + +/* 线条类型-实线 */ +#define HGIMGPROC_LINETYPE_SOLID 1L +/* 线条类型-虚线 */ +#define HGIMGPROC_LINETYPE_DASH 2L + +/* 水印位置-左侧 */ +#define HGIMGPROC_WMPOSTYPE_LEFT 1L +/* 水印位置-上侧 */ +#define HGIMGPROC_WMPOSTYPE_TOP 2L +/* 水印位置-右侧 */ +#define HGIMGPROC_WMPOSTYPE_RIGHT 3L +/* 水印位置-下侧 */ +#define HGIMGPROC_WMPOSTYPE_BOTTOM 4L +/* 水印位置-左上 */ +#define HGIMGPROC_WMPOSTYPE_LEFTTOP 5L +/* 水印位置-右上 */ +#define HGIMGPROC_WMPOSTYPE_RIGHTTOP 6L +/* 水印位置-左下 */ +#define HGIMGPROC_WMPOSTYPE_LEFTBOTTOM 7L +/* 水印位置-右下 */ +#define HGIMGPROC_WMPOSTYPE_RIGHTBOTTOM 8L +/* 水印位置-中间 */ +#define HGIMGPROC_WMPOSTYPE_CENTER 9L +/* 水印位置-自定义 */ +#define HGIMGPROC_WMPOSTYPE_LOCATION 10L + +/* 内部去污 */ +#define HGIMGPROC_DECOTYPE_INSIDE 1L +/* 外部去污 */ +#define HGIMGPROC_DECOTYPE_OUTSIDE 2L + +#pragma pack(push) +#pragma pack(4) + +/* 自动裁剪参数 */ +typedef struct +{ + HGBool convex; /* 黑底填充时的填充方式, HGTRUE为凸多边形填充,HGFALSE为凹多边形填充,默认HGTRUE */ + HGBool fillColor; /* 黑底填充时采用自适应色彩填充,HGFALSE为白色填充,HGTRUE为自适应文稿底色填充,默认HGFALSE */ + HGDouble threshold; /* 二值化阈值,取值范围(0, 255),默认40 */ + HGInt noise; /* 除噪像素,能够消除noise宽度的背景竖条纹干扰,默认8 */ + HGInt indent; /* 轮廓缩进,裁剪、纠偏或者黑底填充时,对探索到的纸张轮廓进行缩进indent像素,默认5 */ + HGBool normalCrop; /* crop deskew fillBlank失效,固定裁切采用最传统的裁切方式,默认HGFALSE */ + HGBool dispersion; /* 是否除色散,默认HGTRUE */ +}HGImgAutoCropParam; + +/* 白底检查参数 */ +typedef struct +{ + HGDouble threshold; /* 默认40 */ + HGInt edge; /* 默认150 */ + HGInt blockSize; /* 默认10 */ + HGDouble devTh; /* 默认50 */ + HGDouble meanTh; /* 默认200 */ +}HGImgBlankCheckParam; + +/* 水印字体参数 */ +typedef struct +{ + HGChar foneName[64]; /* 字体名, windows上为GBK编码, linux上为UTF8编码, 默认宋体 */ + HGUInt fontSize; /* 字号, 默认20 */ + HGBool bold; /* 是否粗体, 默认HGFALSE */ + HGBool underline; /* 是否有下划线, 默认HGFALSE */ + HGBool italic; /* 是否斜体, 默认HGFALSE */ + HGBool strikeout; /* 是否有删除线, 默认HGFALSE */ +}HGImgWatermarkFontParam; + +/* 去底色参数 */ +typedef struct +{ + HGInt threshold; /* 默认100 */ + HGInt offset; /* 默认0 */ + HGInt range; /* 默认40 */ +}HGImgFaceBkColorParam; + +#pragma pack(pop) + +/* 图像缩放 +* 参数: +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 3) interpolation: in, 插值方式, 参见HGIMGPROC_INTERPOTYPE_* +* 说明: +* 1) 操作的只是图像的ROI区域 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage不能是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ResizeImage(HGImage image, HGImage destImage, HGUInt interp); + +/* +* 图像色彩调整 +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 3) brightness: in, 亮度增加值, -255至255之间 +* 4) contrast: in, 对比度增加值, -127至127之间 +* 5) gamma: 伽马增加值, 0.1至5.0之间 +* 说明: +* 1) 操作的只是图像的ROI区域, ROI区域的大小必须一致 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageAdjustColors(HGImage image, HGImage destImage, + HGInt brightness, HGInt contrast, HGFloat gamma); + +/* +* 图像自动裁剪 +* 1) image: in, 图像句柄 +* 2) autoCrop: in, 是否自动裁剪, 为HGTRUE则忽略destWidth和destHeight +* 3) deskew: in, 是否纠偏 +* 4) fillBlank: in, 是否进行黑底填充 +* 5) param: in, 参数, 为NULL时使用默认参数 +* 6) destWidth: in, 目标图像宽度 +* 7) destHeight: in, 目标图像高度 +* 8) destType: in, 目标图像类型, 0表示和image一样 +* 9) destOrigin: in, 目标图像数据排列方式, 0表示和image一样 +* 10) destImage: out, 输出的目标图像句柄, 不用的时候需要调用HGBase_DestroyImage销毁 +* 说明: +* 1) 操作的只是image的ROI区域 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageAutoCrop(HGImage image, HGBool autoCrop, HGBool deskew, HGBool fillBlank, const HGImgAutoCropParam* param, + HGUInt destWidth, HGUInt destHeight, HGUInt destType, HGUInt destOrigin, HGImage* destImage); + +/* 判断图像是否是空白 +* 1) image: in, 图像句柄 +* 2) param: in, 参数, 为NULL时使用默认参数 +* 3) blank: out, HGTRUE为空白图像, HGFALSE为非空白图像 +* 说明: +* 1) 操作的只是image的ROI区域 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageBlankCheck(HGImage image, const HGImgBlankCheckParam *param, HGBool *blank); + +/* 图像画线 +* 1) image: in, 图像句柄 +* 2) x1: in, 第一个点x坐标 +* 3) y1: in, 第一个点y坐标 +* 4) x2: in, 第二个点x坐标 +* 5) y2: in, 第二个点y坐标 +* 6) color: in, 颜色 +* 7) width: in, 线宽 +* 8) type: in, 表示线类型, 参见HGIMGPROC_LINETYPE_* +* 说明: +* 1) 操作的只是图像的ROI区域 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageDrawLine(HGImage image, HGInt x1, HGInt y1, HGInt x2, HGInt y2, + HGColor color, HGUInt width, HGUInt type); + +/* 添加图像水印 +* 1) image: in, 图像句柄 +* 2) text: 水印文本, windows上为GBK编码, linux上为UTF8编码 +* 3) color: 颜色 +* 4) posType: 位置, 见HGIMGPROC_WMPOSTYPE_* +* 5) locationX: 当posType为HGIMGPROC_WMPOSTYPE_LOCATION时表示x坐标 +* 6) locationY: 当posType为HGIMGPROC_WMPOSTYPE_LOCATION时表示y坐标 +* 7) fontParam: 字体参数, 为NULL时使用默认参数 +* 说明: +* 1) 操作的只是图像的ROI区域 +*/ +HGEXPORT HGResult HGAPI HGImgProc_AddImageWatermark(HGImage image, const HGChar *text, HGColor color, HGUInt posType, + HGInt locationX, HGInt locationY, const HGImgWatermarkFontParam *fontParam); + +/* 消除文稿纸张底色 +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 3) param: in, 参数, 为NULL时使用默认参数 +* 说明: +* 1) 操作的只是图像的ROI区域, ROI区域的大小必须一致 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageFadeBkColor(HGImage image, HGImage destImage, const HGImgFaceBkColorParam *param); + +/* 图像去污 +* 1) image: in, 源图像句柄 +* 2) destImage: in, 目标图像句柄 +* 3) decoType: in, 去污类型, 参见HGIMGPROC_DECOTYPE_* +* 4) x: in, 选择区域的x坐标 +* 5) y: in, 选择区域的y坐标 +* 6) width: in, 选择区域的宽 +* 7) height: in, 选择区域的高 +* 说明: +* 1) 操作的只是图像的ROI区域, ROI区域的大小必须一致 +* 2) 源图像和目标图像的type必须一样 +* 3) 自动处理origon不一致的情况 +* 4) image和destImage可以是同一个句柄 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageDecontamination(HGImage image, HGImage destImage, HGUInt decoType, HGUInt x, HGUInt y, + HGUInt width, HGUInt height, HGColor color); + +#endif /* __HGIMGPROC_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgproc/HGImgProcErr.h b/app/sdk/include/imgproc/HGImgProcErr.h new file mode 100644 index 0000000..cd6818b --- /dev/null +++ b/app/sdk/include/imgproc/HGImgProcErr.h @@ -0,0 +1,13 @@ +#ifndef __HGIMGPROCERR_H__ +#define __HGIMGPROCERR_H__ + +/* 一般错误 */ +#define HGIMGPROC_ERR_FAIL 0x00003001L + +/* OCR初始化错误 */ +#define HGIMGPROC_ERR_OCRINIT 0x00003002L + +/* OCR错误 */ +#define HGIMGPROC_ERR_OCR 0x00003003L + +#endif /* __HGIMGPROCERR_H__ */ \ No newline at end of file diff --git a/app/sdk/include/imgproc/HGOCR.h b/app/sdk/include/imgproc/HGOCR.h new file mode 100644 index 0000000..0e33414 --- /dev/null +++ b/app/sdk/include/imgproc/HGOCR.h @@ -0,0 +1,85 @@ +#ifndef __HGOCR_H__ +#define __HGOCR_H__ + +#include "../base/HGDef.h" +#include "../base/HGBaseErr.h" +#include "HGImgProcErr.h" +#include "../base/HGImage.h" + +HG_DECLARE_HANDLE(HGOCRMgr); +HG_DECLARE_HANDLE(HGOCRRet); + +/* algo */ +#define HGIMGPROC_OCRALGO_DEFAULT 0L +#define HGIMGPROC_OCRALGO_HANVON 1L +#define HGIMGPROC_OCRALGO_TESSERACT 2L + +/* RTF */ +#define HGIMGPROC_OCROUTTYPE_RTF 1L +/* XLS */ +#define HGIMGPROC_OCROUTTYPE_XLS 2L +/* TXT */ +#define HGIMGPROC_OCROUTTYPE_TXT 3L +/* PDF */ +#define HGIMGPROC_OCROUTTYPE_PDF 4L +/* OFD */ +#define HGIMGPROC_OCROUTTYPE_OFD 5L + +/* 未旋转 */ +#define HGIMGPROC_OCRTEXTDIRECT_ORI 1L +/* 顺时针旋转了90度 */ +#define HGIMGPROC_OCRTEXTDIRECT_RIGHT 2L +/* 逆时针旋转了90度 */ +#define HGIMGPROC_OCRTEXTDIRECT_LEFT 3L +/* 旋转了180度 */ +#define HGIMGPROC_OCRTEXTDIRECT_180 4L + +/* 多页OCR进度 +*/ +typedef HGInt (HGAPI *HGImageListOcrFunc)(HGUInt total, HGUInt now, HGPointer param); + +/* 初始化OCR模块 +*/ +HGEXPORT HGResult HGAPI HGImgProc_CreateOCRMgr(HGUInt algo, HGOCRMgr *ocrMgr); + +/* 反初始化OCR模块 +*/ +HGEXPORT HGResult HGAPI HGImgProc_DestroyOCRMgr(HGOCRMgr ocrMgr); + +/* 图像OCR +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageOCR(HGOCRMgr ocrMgr, HGImage image, HGOCRRet *ocrRet); + +/* 销毁OCR结果 +*/ +HGEXPORT HGResult HGAPI HGImgProc_DestroyOCRRet(HGOCRRet ocrRet); + +/* 获取OCR结果块数量 +*/ +HGEXPORT HGResult HGAPI HGImgProc_GetOCRRetBlockCount(HGOCRRet ocrRet, HGUInt *count); + +/* 获取OCR结果块文本 +*/ +HGEXPORT HGResult HGAPI HGImgProc_GetOCRRetBlockText(HGOCRRet ocrRet, HGUInt index, const HGChar **text); + +/* 图像OCR到文件 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageOCRToFile(HGOCRMgr ocrMgr, HGImage image, HGUInt outType, const HGChar *outFileName); + +/* 获取图像识别方向 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageTextDirectOCR(HGOCRMgr ocrMgr, HGImage image, HGUInt *direct); + +/* 添加到图像OCR列表 +*/ +HGEXPORT HGResult HGAPI HGImgProc_AddToImageOCRList(HGOCRMgr ocrMgr, HGImage image); + +/* 清理图像OCR列表 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ClearImageOCRList(HGOCRMgr ocrMgr); + +/* 图像列表OCR到文件 +*/ +HGEXPORT HGResult HGAPI HGImgProc_ImageListOCRToFile(HGOCRMgr ocrMgr, HGUInt outType, const HGChar* outFileName, HGImageListOcrFunc func, HGPointer param); + +#endif /* __HGOCR_H__ */ \ No newline at end of file diff --git a/app/sdk/lib/x64/Release/HGBase.lib b/app/sdk/lib/x64/Release/HGBase.lib new file mode 100644 index 0000000..09169e2 Binary files /dev/null and b/app/sdk/lib/x64/Release/HGBase.lib differ diff --git a/app/sdk/lib/x64/Release/HGImgFmt.lib b/app/sdk/lib/x64/Release/HGImgFmt.lib new file mode 100644 index 0000000..81ee7b7 Binary files /dev/null and b/app/sdk/lib/x64/Release/HGImgFmt.lib differ diff --git a/app/sdk/lib/x64/Release/HGImgProc.lib b/app/sdk/lib/x64/Release/HGImgProc.lib new file mode 100644 index 0000000..31efcf5 Binary files /dev/null and b/app/sdk/lib/x64/Release/HGImgProc.lib differ diff --git a/app/sdk/lib/x64/Release/sane.lib b/app/sdk/lib/x64/Release/sane.lib new file mode 100644 index 0000000..2cd7820 Binary files /dev/null and b/app/sdk/lib/x64/Release/sane.lib differ diff --git a/app/sdk/lib/x86/Release/HGBase.lib b/app/sdk/lib/x86/Release/HGBase.lib new file mode 100644 index 0000000..fd09bdd Binary files /dev/null and b/app/sdk/lib/x86/Release/HGBase.lib differ diff --git a/app/sdk/lib/x86/Release/HGImgFmt.lib b/app/sdk/lib/x86/Release/HGImgFmt.lib new file mode 100644 index 0000000..a6e02b5 Binary files /dev/null and b/app/sdk/lib/x86/Release/HGImgFmt.lib differ diff --git a/app/sdk/lib/x86/Release/HGImgProc.lib b/app/sdk/lib/x86/Release/HGImgProc.lib new file mode 100644 index 0000000..52737be Binary files /dev/null and b/app/sdk/lib/x86/Release/HGImgProc.lib differ diff --git a/app/sdk/lib/x86/Release/sane.lib b/app/sdk/lib/x86/Release/sane.lib new file mode 100644 index 0000000..7a1aeeb Binary files /dev/null and b/app/sdk/lib/x86/Release/sane.lib differ diff --git a/app/utility/HGString.cpp b/app/utility/HGString.cpp new file mode 100644 index 0000000..aa05604 --- /dev/null +++ b/app/utility/HGString.cpp @@ -0,0 +1,51 @@ +#include "HGString.h" +#include "../modules/base/HGDef.h" +#include "../modules/base/HGInc.h" +#include + +#if defined(HG_CMP_MSC) +static std::string AnsiToUtf8(const char* text) +{ + int wlen = ::MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0); + WCHAR* pUnicode = new WCHAR[wlen]; + ::MultiByteToWideChar(CP_ACP, 0, text, -1, pUnicode, wlen); + int len = ::WideCharToMultiByte(CP_UTF8, 0, pUnicode, -1, NULL, 0, NULL, NULL); + CHAR* pUTF8 = new CHAR[len]; + ::WideCharToMultiByte(CP_UTF8, 0, pUnicode, -1, pUTF8, len, NULL, NULL); + delete[] pUnicode; + std::string ret = pUTF8; + delete[] pUTF8; + return ret; +} +static std::string Utf8ToAnsi(const char* text) +{ + int wlen = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0); + WCHAR* pUnicode = new WCHAR[wlen]; + ::MultiByteToWideChar(CP_UTF8, 0, text, -1, pUnicode, wlen); + int len = ::WideCharToMultiByte(CP_ACP, 0, pUnicode, -1, NULL, 0, NULL, NULL); + CHAR* pAnsi = new CHAR[len]; + ::WideCharToMultiByte(CP_ACP, 0, pUnicode, -1, pAnsi, len, NULL, NULL); + delete[] pUnicode; + std::string ret = pAnsi; + delete[] pAnsi; + return ret; +} +#endif + +std::string Utf8ToStdString(const std::string& utf8Str) +{ +#if defined(HG_CMP_MSC) + return Utf8ToAnsi(utf8Str.c_str()); +#else + return utf8Str; +#endif +} + +std::string StdStringToUtf8(const std::string& stdStr) +{ +#if defined(HG_CMP_MSC) + return AnsiToUtf8(stdStr.c_str()); +#else + return stdStr; +#endif +} \ No newline at end of file diff --git a/app/utility/HGString.h b/app/utility/HGString.h new file mode 100644 index 0000000..5040d1e --- /dev/null +++ b/app/utility/HGString.h @@ -0,0 +1,14 @@ +#ifndef __HGSTRING_H__ +#define __HGSTRING_H__ + +#include + +// 标准字符串:windows下为ansi编码,linux下为utf8编码 + +// UTF8转标准字符串 +std::string Utf8ToStdString(const std::string& utf8Str); + +// 标准字符串转UTF8 +std::string StdStringToUtf8(const std::string& stdStr); + +#endif /* __HGSTRING_H__ */ \ No newline at end of file diff --git a/doc/config.json b/doc/config.json new file mode 100644 index 0000000..8156e2a --- /dev/null +++ b/doc/config.json @@ -0,0 +1,218 @@ +{ + "global": { + "vid-org": 12402, + "pid-org": 512, + "vid-to": 12402, + "pid-to": 569 + }, + "1": { + "name": "test-1", + "title": "拨码开关校验", + "man": true, + "err-level": "fatal" + }, + "2": { + "name": "test-2", + "title": "检查船型开关功能", + "man": true, + "err-level": "fatal" + }, + "3": { + "name": "test-3", + "title": "设备上电并观察开机状态", + "man": true, + "err-level": "fatal" + }, + "4": { + "name": "test-4", + "title": "检查液晶显示", + "man": true, + "err-level": "fatal" + }, + "5": { + "name": "test-5", + "title": "清理纸道功能确认", + "man": true, + "err-level": "fatal" + }, + "6": { + "name": "test-6", + "title": "按键功能检测", + "man": true, + "err-level": "fatal" + }, + "7": { + "name": "test-7", + "title": "计数模式检测", + "man": true, + "err-level": "fatal" + }, + "8": { + "name": "test-8", + "title": "歪斜检测", + "man": false, + "err-level": "fatal" + }, + "9": { + "name": "test-9", + "title": "分纸电机检测", + "man": false, + "err-level": "fatal" + }, + "10": { + "name": "test-10", + "title": "CIS原图初检", + "man": false, + "err-level": "fatal" + }, + "11": { + "name": "test-11", + "title": "主机风扇功能检测", + "man": false, + "err-level": "fatal" + }, + "12": { + "name": "test-12", + "title": "超声波模块检验", + "man": false, + "err-level": "fatal" + }, + "13": { + "name": "test-13", + "title": "LED灯状态检查", + "man": false, + "err-level": "fatal" + }, + "14": { + "name": "test-14", + "title": "复位检查", + "man": false, + "err-level": "fatal" + }, + "15": { + "name": "test-15", + "title": "走纸检查", + "man": false, + "err-level": "fatal" + }, + "16": { + "name": "test-16", + "title": "开盖传感器检查", + "man": false, + "err-level": "fatal" + }, + "17": { + "name": "test-17", + "title": "扫描传感器检查", + "man": false, + "err-level": "fatal" + }, + "18": { + "name": "test-18", + "title": "配置速度模式", + "man": false, + "err-level": "fatal" + }, + "19": { + "name": "test-19", + "title": "放置校正纸", + "man": false, + "err-level": "fatal" + }, + "20": { + "name": "test-20", + "title": "自动平场校正", + "man": false, + "err-level": "fatal" + }, + "21": { + "name": "test-21", + "title": "重启设备", + "man": false, + "err-level": "fatal" + }, + "22": { + "name": "test-22", + "title": "扫描图像质量确认", + "man": false, + "err-level": "fatal" + }, + "23": { + "name": "test-23", + "title": "色卡纸成像质量评估", + "man": false, + "err-level": "fatal" + }, + "24": { + "name": "test-24", + "title": "色卡纸偏色成像质量评估", + "man": false, + "err-level": "fatal" + }, + "25": { + "name": "test-25", + "title": "清晰度质量评估", + "man": false, + "err-level": "fatal" + }, + "26": { + "name": "test-26", + "title": "畸变修正", + "man": false, + "err-level": "fatal" + }, + "27": { + "name": "test-27", + "title": "设置休眠", + "man": false, + "err-level": "fatal" + }, + "28": { + "name": "test-28", + "title": "歪斜挡位检测", + "man": false, + "err-level": "fatal" + }, + "29": { + "name": "test-29", + "title": "分纸强度检测", + "man": false, + "err-level": "fatal" + }, + "30": { + "name": "test-30", + "title": "机械走纸倾斜检测", + "man": false, + "err-level": "fatal" + }, + "31": { + "name": "test-31", + "title": "单张测试1", + "man": false, + "err-level": "fatal" + }, + "32": { + "name": "test-32", + "title": "单张测试2", + "man": false, + "err-level": "fatal" + }, + "33": { + "name": "test-33", + "title": "单张测试3", + "man": false, + "err-level": "fatal" + }, + "34": { + "name": "test-34", + "title": "压力测试2轮", + "man": false, + "err-level": "fatal" + }, + "35": { + "name": "test-35", + "title": "清除滚轴计数", + "man": false, + "err-level": "fatal" + } +} \ No newline at end of file