#include <cmath>
#include <qimage.h>
#include <qprinter.h>
#include <qprintdialog.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <QTextCodec>
#include "mapview.rh"
#include "struct.h"
struct BORDER
{
DOUBLEPOINT UpLeft;
DOUBLEPOINT UpRight;
DOUBLEPOINT DownRight;
DOUBLEPOINT DownLeft;
DOUBLEPOINT UpLeftLast;
};
extern "C"
{
void SetupParam(HMAP hmap, SCRIPTPARAM *ScriptParam, DFRAME *FrameTrap);
void msInitPrintParam(MAPPRINTPARMEX *printParam, BORDER border, double frameAngle, bool isClockWise);
long int msPrintMap(HMAP hMap, SCRIPTPARAM *scriptparam, MAPPRINTPARMEX *printparam, QPrinter *printer);
}
// Максимальный характерный размер "элементарной"
// страницы для печати
const int MAXPAGEWIDTH = 4000;
const int MAXPAGEHEIGHT = 4000;
long int msPrintOneSimplePage(HMAP hMap, QPainter *p, int px, int py, int cx, int cy, int cw, int ch,
double printprecisionX, double printprecisionY);
long int msPrintOnePage(HMAP hMap, QPainter *p, int cx, int cy, int cw, int ch,
double printprecisionX, double printprecisionY);
// Инициализировать параметры печати
// printparam - структура параметров печати
// border - структура координат рамки выделения
// frameAngle - угол поворота рамки выделения
// isClockWise - признак того, что точки рамки выделения выбраны по часовой стрелке
void msInitPrintParam(MAPPRINTPARMEX *printParam, BORDER border, double frameAngle, bool isClockWise) // 24/08/15 Савелов
{
// Определить координаты рамки печати
DFRAME *planeFrame = &printParam->PlaneFrame;
// В режиме выбора прямоугольной рамки поменять местами
// координаты точек прямоугольника
if (printParam->TurnFrame == 0)
{
DFRAME tempFrame = *planeFrame;
planeFrame->X1 = tempFrame.X2;
planeFrame->Y1 = tempFrame.Y1;
planeFrame->X2 = tempFrame.X1;
planeFrame->Y2 = tempFrame.Y2;
return;
}
if (frameAngle < 0)
{
if (isClockWise == true)
{
planeFrame->X1 = border.DownRight.x;
planeFrame->Y1 = border.DownRight.y;
planeFrame->X2 = border.UpLeft.x;
planeFrame->Y2 = border.UpLeft.y;
}
else
{
planeFrame->X1 = border.UpRight.x;
planeFrame->Y1 = border.UpRight.y;
planeFrame->X2 = border.DownLeft.x;
planeFrame->Y2 = border.DownLeft.y;
}
}
// Определить угол поворота карты
double *printAngle = &printParam->Angle;
if (frameAngle < -M_PI/2 && frameAngle > -M_PI)
*printAngle = fabs(frameAngle) - M_PI/2;
else if (frameAngle < 0 && frameAngle > -M_PI/2)
*printAngle = fabs(frameAngle) - M_PI/2;
else
*printAngle = -(fabs(frameAngle) - M_PI/2);
}
//-----------------------------------------------------------------
// Печать выбранного фрагмента карты
//-----------------------------------------------------------------
long int msPrintMap(HMAP hMap, SCRIPTPARAM *scriptparam, MAPPRINTPARMEX *printparam, QPrinter *printer)
{
if (hMap == 0)
return 0;
QPainter p;
QTextCodec *MainCodec = QTextCodec::codecForName("KOI8-R");
// Установить параметры принтера
if (strlen(scriptparam->NamePrinter) > 0)
{
printer->setPrinterName(MainCodec->toUnicode(scriptparam->NamePrinter));
}
else if (strlen(scriptparam->NameInputPost) > 0)
{
printer->setOutputFormat(QPrinter::PdfFormat);
printer->setOutputFileName(MainCodec->toUnicode(scriptparam->NameInputPost));
}
else
return 0;
if ( !p.begin(printer) )
return 0;
// Повернуть карту
if (printparam->TurnFrame != 0)
mapSetupTurn(hMap, printparam->Angle, 0);
// Запросить точный масштаб отображения карты
double oldscale = mapGetRealShowScale(hMap);
// Установить точный масштаб отображения карты
mapSetRealShowScale(hMap, scriptparam->Scale);
// Функции настройки ядра согласно данным принтера
double oldhor = mapGetHorizontalScreenPrecision();
double oldver = mapGetVerticalScreenPrecision();
double printprecisionX = printer->physicalDpiX() * 1000 / 25.4;
double printprecisionY = printer->physicalDpiY() * 1000 / 25.4;
mapSetScreenPrecisionEx(printprecisionX, printprecisionY);
long int x = 0, y = 0;
mapChangeViewScale(hMap, &x, &y, 1.0);
// Печать нескольких копий
int copyCount = printer->copyCount();
for (int copyId = 0; copyId < copyCount; copyId++)
{
if(copyId != 0)
printer->newPage();
int cw = 800, ch = 600, cx = 0, cy = 0;
// Переведем в пикселы габариты печати
double x1 = printparam->PlaneFrame.X1;
double y1 = printparam->PlaneFrame.Y1;
double x2 = printparam->PlaneFrame.X2;
double y2 = printparam->PlaneFrame.Y2;
mapPlaneToPicture(hMap, &x1, &y1);
mapPlaneToPicture(hMap, &x2, &y2);
int xbegin = x1;
// Запомним левую и нижнюю границу в пикселах
cx = x2;
cy = y2;
// Габариты области печати в пикселах
cw = x2 - x1;
ch = y2 - y1;
// Габариты страницы формата принтера в пикселах
QRectF rectf = printer->pageRect(QPrinter::DevicePixel);
int wpage = rectf.width();
int hpage = rectf.height();
// Количество страниц по высоте
int ss = (ch + hpage - 1) / hpage;
// Количество страниц по ширине
int cc = (cw + wpage - 1) / wpage;
for (int s = 0; s < ss; s++)
{
y2 = y1 + hpage;
if (y2 > cy) y2 = cy;
x1 = xbegin;
for (int c = 0; c < cc; c++)
{
if (s + c > 0) printer->newPage();
x2 = x1 + wpage;
if (x2 > cx) x2 = cx;
cw = x2 - x1;
ch = y2 - y1;
// Печать одной страницы
msPrintOnePage(hMap, &p, x1, y1, cw, ch, printprecisionX, printprecisionY);
x1 = x2;
}
y1 = y2;
}
}
p.end();
mapSetScreenPrecisionEx(oldhor, oldver);
mapChangeViewScale(hMap, &x, &y, 1.0);
// Установить точный масштаб отображения карты
mapSetRealShowScale(hMap, oldscale);
// Инвертировать поворот карты
if (printparam->TurnFrame != 0)
mapSetupTurn(hMap, 0, 0);
}
//-----------------------------------------------------------------
// Печать одной страницы
// hMap - указатель на карту
// p - указатель на текущий класс отрисовки Qt
// cx - начало области отрисовки на карте в пикселах по x
// cy - начало области отрисовки на карте в пикселах по y
// cw - ширина области отрисовки на карте в пикселах
// ch - высота области отрисовки на карте в пикселах
// printprecisionX - текущее разрешение карты для принтера по X
// printprecisionY - текущее разрешение принтера карты для по Y
//-----------------------------------------------------------------
long int msPrintOnePage(HMAP hMap, QPainter *p, int cx, int cy, int cw, int ch, double printprecisionX, double printprecisionY)
{
// Запомнить координаты правого нижнего угла
int cx2 = cx + cw;
int cy2 = cy + ch;
// Получить число "элементарных" страниц для печати
int horSimplePagesNum = ceil((double)cw / MAXPAGEWIDTH);
int verSimplePagesNum = ceil((double)ch / MAXPAGEHEIGHT);
// Если размер "комплексной" страницы укладывается в одну элементарную -
// распечатать "как есть"
if(horSimplePagesNum == 1 && verSimplePagesNum == 1)
{
msPrintOneSimplePage(hMap, p, 0, 0, cx, cy, cw, ch,
printprecisionX, printprecisionY);
return 0;
}
// Распечатать набор "элементарных" страниц
int pageY = cy;
// Положение на одном листе
int pagePY = 0;
for(int verId = 0; verId < verSimplePagesNum; verId++)
{
int pageX = cx;
int pagePX = 0;
for(int horId = 0; horId < horSimplePagesNum; horId++)
{
// Вычислить размер печатаемой страницы
int printWidth = MAXPAGEWIDTH, printHeight = MAXPAGEHEIGHT;
if(pageX + MAXPAGEWIDTH > cx2)
printWidth = cx2 - pageX;
if(pageY + MAXPAGEHEIGHT > cy2)
printHeight = cy2 - pageY;
// Напечатать "элементарную" страницу
int res = msPrintOneSimplePage(hMap, p, pagePX, pagePY, pageX, pageY, printWidth, printHeight,
printprecisionX, printprecisionY);
if(res == -1) {
fprintf(stderr, "cannot print simple page\n");
return -1;
}
// Сместиться на лист вправо
pageX += MAXPAGEWIDTH;
pagePX += MAXPAGEWIDTH;
}
// Сместиться на лист вниз
pageY += MAXPAGEHEIGHT;
pagePY += MAXPAGEHEIGHT;
}
return 0;
}
//-----------------------------------------------------------------
// Печать одной страницы
// hMap - указатель на карту
// p - указатель на текущий класс отриовки Qt
// px - начало области отрисовки на листе в пикселах по x
// py - начало области отрисовки на листе в пикселах по y
// cx - начало области отрисовки на карте в пикселах по x
// cy - начало области отрисовки на карте в пикселах по y
// cw - ширина области отрисовки на карте в пикселах
// ch - высота области отрисовки на карте в пикселах
// printprecisionX - текущее разрешение карты для принтера по X
// printprecisionY - текущее разрешение принтера карты для по Y
//-----------------------------------------------------------------
long int msPrintOneSimplePage(HMAP hMap, QPainter *p, int px, int py, int cx, int cy, int cw, int ch, double printprecisionX, double printprecisionY)
{
// Размер строки в байтах
int allignwidth = cw * CELLSIZE;
// Размер DIB в памяти
int size = allignwidth * ch;
// Указатель на DIB в памяти
char *bits = AllocateTheMemory(size);
if(bits == NULL) // 09/02/15
return -1;
memset(bits, 0, size);
// Формирование структуры отрисовки карты
XIMAGEDESC Ximagedesc;
Ximagedesc.Point = bits; // Адрес начала области пикселов
Ximagedesc.Width = cw; // Ширина строки в пикселах
Ximagedesc.Height = ch; // Число строк
Ximagedesc.Depth = CELLSIZE * 8; // Размер элемента в битах (8,15,16,24,32)
Ximagedesc.CellSize = CELLSIZE; // Размер элемента(пиксела) в байтах
Ximagedesc.RowSize = allignwidth;// Ширина строки в байтах
RECT RectDraw;
RectDraw.left = cx ;
RectDraw.top = cy ;
RectDraw.right = cx + cw;
RectDraw.bottom = cy + ch;
long oldViewType = mapSetViewType(hMap, VT_PRINTRST);
// Установим белый цвет фона
COLORREF oldback = mapGetBackColor(hMap);
mapSetBackColor(hMap, 0x0FFFFFF);
// Отобразим фрагмент карты в памяти
mapPaintToXImage(hMap, &Ximagedesc, 0, 0, &RectDraw);
mapSetBackColor(hMap, oldback);
mapSetViewType(hMap, oldViewType);
// Создать QImage по XImage
QImage image((const uchar *)bits, cw, ch, allignwidth, QImage::Format_RGB32);
// Отобразить карту на принтер средствами Qt
p->drawImage(px, py, image, 0, 0, cw, ch);
FreeTheMemory(bits);
return 0;
} |