2 Star 0 Fork 0

mirrors_anthonyfok/scantailor

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
ImageTransformation.h 7.57 KB
一键复制 编辑 原始数据 按行查看 历史
/*
Scan Tailor - Interactive post-processing tool for scanned pages.
Copyright (C) Joseph Artsimovich <[email protected]>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IMAGETRANSFORMATION_H_
#define IMAGETRANSFORMATION_H_
#include "OrthogonalRotation.h"
#include "Dpi.h"
#include <QTransform>
#include <QPolygonF>
#include <QRectF>
/**
* \brief Provides a transformed view of an image.
*
* \anchor transformations
* Suppose we need to make the following transformations
* to a particular image (in this order):
* -# Scale it, to achieve the desired optical resolution.
* It's generally done only in case input had different
* horizontal and vertical DPI. We refer to this operation
* as pre-scale.
* -# Rotate it by a multiple of 90 degrees,
* swapping its width and height if necessary.
* That's done on the "Fix Orientation" stage. We refer to
* this operation as pre-rotate.
* -# Crop it, reducing its width and height.
* That's done on the "Split Pages" stage, where we crop
* to the bounding box of a polygon formed by cutters and
* remaining image edges. We refer to this operation as
* pre-crop.
* -# Apply a rotation around the image center,
* increasing its width and height as necessary.
* That's done on the "Deskew" stage. We refer to this
* operation as post-rotate.
* -# Apply another crop, or maybe extend the image boundaries,
* in order to place the required margins around content.
* That's done on the "Margins" stage. We refer to this operation
* as post-crop.
* -# Scale the image to desired DPI. That's done on the "Output" stage.
* We refer to this operation as post-scale.
*
* Instead of actually modifying the image, we provide
* a mapping from the original image coordinates to the new ones.
* Note that all transformation steps are optional.
*/
class ImageTransformation
{
public:
// Member-wise copying is OK.
ImageTransformation(QRectF const& orig_image_rect, Dpi const& orig_dpi);
~ImageTransformation();
/**
* \brief Set the 1st step transformation, recalculating the following ones.
*
* \see \ref transformations Transformations.
*/
void preScaleToDpi(Dpi const& dpi);
/**
* \brief Set the 1st step transformation, recalculating the following ones.
*
* Suppose the original image DPI is 300x600. This will scale it to
* 300x300, the minimum of two.
*
* \note This transformation is applied automatically on construction.
*
* \see \ref transformations Transformations.
*/
void preScaleToEqualizeDpi();
/**
* \brief Get the original image DPI.
*/
Dpi const& origDpi() const { return m_origDpi; }
/**
* \brief Get the target DPI for pre-scaling.
*
* Note that if the original DPI was assymetric, pre-scaling to
* a symmetric DPI will be applied implicitly.
*/
Dpi const& preScaledDpi() const { return m_preScaledDpi; }
/**
* \brief Set the 2nd step transformation, resetting the following ones.
*
* \see \ref transformations Transformations.
*/
void setPreRotation(OrthogonalRotation rotation);
/**
* \brief Returns the 2nd step rotation.
*/
OrthogonalRotation preRotation() const { return m_preRotation; }
/**
* \brief Set the 3rd step transformation, resetting the following ones.
*
* Providing a null polygon has the same effect as providing a polygon
* that covers the entire image. A crop area that exceedes the image
* is allowed.
*
* \see \ref transformations Transformations.
*/
void setPreCropArea(QPolygonF const& area);
/**
* \brief Get the effective pre-crop area in pre-rotated coordinates.
*
* If pre-crop area was explicitly set with setPreCropArea(), then
* this function returns it as is. Otherwise, the whole available
* area is returned.
*/
QPolygonF const& preCropArea() const { return m_preCropArea; }
/**
* \brief Returns the pre-crop area after all transformations.
*
* If no pre-crop area was set, the whole image is assumed to be
* the pre-crop area.
*/
QPolygonF const& resultingPreCropArea() const { return m_resultingPreCropArea; }
/**
* \brief Set the 4th step transformation, resetting the following ones.
*
* \see \ref transformations Transformations.
*/
void setPostRotation(double degrees);
/**
* \brief Returns the 4th step rotation in degrees, as specified.
*/
double postRotation() const { return m_postRotation; }
/**
* \brief Returns the sine of the 4th step rotation angle.
*/
double postRotationSin() const { return m_postRotateXform.m12(); }
/**
* \brief Returns the cosine of the 3rd step rotation angle.
*/
double postRotationCos() const { return m_postRotateXform.m11(); }
/**
* \brief Set the 5th step transformation, resetting the following ones.
*/
void setPostCropArea(QPolygonF const& area);
/**
* \brief Returns the post-crop area after all transformations.
*
* If no post-crop area was set, the whole image is assumed to be
* the post-crop area.
*/
QPolygonF const& resultingPostCropArea() const { return m_resultingPostCropArea; }
/**
* \brief Set the 6th step transformation.
*
* Passing a null (default constructed) Dpi means "don't apply post-scaling".
*/
void postScaleToDpi(Dpi const& dpi);
/**
* \brief Returns the transformation matrix from the original
* to resulting image coordinates.
*/
QTransform const& transform() const { return m_transform; }
/**
* \brief Returns the transformation matrix from the resulting
* to original image coordinates.
*/
QTransform const& transformBack() const { return m_invTransform; }
/**
* \brief Returns the original image rectangle, as specified.
*/
QRectF const& origRect() const { return m_origRect; }
/**
* \brief Returns the resulting image rectangle.
*
* The top-left corner of the resulting rectangle is expected
* to be very close to (0, 0), assuming the original rectangle
* had it at (0, 0), but it's not guaranteed to be exactly there.
*/
QRectF const& resultingRect() const { return m_resultingRect; }
private:
QTransform calcCropXform(QPolygonF const& crop_area);
QTransform calcPostRotateXform(double degrees);
QTransform calcPostScaleXform(Dpi const& target_dpi);
void resetPreCropArea();
void resetPostRotation();
void resetPostCrop();
void resetPostScale();
void update();
QTransform m_preScaleXform;
QTransform m_preRotateXform;
QTransform m_preCropXform;
QTransform m_postRotateXform;
QTransform m_postCropXform;
QTransform m_postScaleXform;
QTransform m_transform;
QTransform m_invTransform;
double m_postRotation;
QRectF m_origRect;
QRectF m_resultingRect; // Managed by update().
QPolygonF m_preCropArea;
QPolygonF m_resultingPreCropArea; // Managed by update().
QPolygonF m_postCropArea;
QPolygonF m_resultingPostCropArea; // Managed by update().
Dpi m_origDpi;
Dpi m_preScaledDpi; // Always set, as preScaleToEqualizeDpi() is called from the constructor.
Dpi m_postScaledDpi; // Default constructed object if no post-scaling.
OrthogonalRotation m_preRotation;
};
#endif
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mirrors_anthonyfok/scantailor.git
[email protected]:mirrors_anthonyfok/scantailor.git
mirrors_anthonyfok
scantailor
scantailor
master

搜索帮助