[mapguide-commits] r1380 - trunk/MgDev/Common/Stylization
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Tue Mar 27 12:13:33 EDT 2007
Author: waltweltonlair
Date: 2007-03-27 12:13:32 -0400 (Tue, 27 Mar 2007)
New Revision: 1380
Modified:
trunk/MgDev/Common/Stylization/DWFRenderer.cpp
trunk/MgDev/Common/Stylization/GDRenderer.cpp
trunk/MgDev/Common/Stylization/GDUtils.cpp
trunk/MgDev/Common/Stylization/GDW2DRewriter.cpp
trunk/MgDev/Common/Stylization/W2DRewriter.cpp
trunk/MgDev/Common/Stylization/W2DRewriter.h
Log:
Finish adding support for rotated images in DWFRender for the
new symbolization. In the case of RGB / RGBA format images
I used some existing code in W2DRewriter (which I moved to
a separate helper method). In the case of PNG images there
was no existing image rotation code. I implemented it by
using functionality from GD. GD lets you load a PNG and do
generic image operations like resampling and rotation. Once
we have the scaled/rotated image we save the updated PNG
image to the DWF output stream.
Modified: trunk/MgDev/Common/Stylization/DWFRenderer.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/DWFRenderer.cpp 2007-03-27 00:23:56 UTC (rev 1379)
+++ trunk/MgDev/Common/Stylization/DWFRenderer.cpp 2007-03-27 16:13:32 UTC (rev 1380)
@@ -54,14 +54,24 @@
#include "ObservationMesh.h"
+#include "W2DRewriter.h"
+#include "UnicodeString.h"
+#include "SLDSymbols.h"
+
+//GD headers
+#include "gd.h"
+
using namespace DWFToolkit;
using namespace DWFCore;
using namespace std;
-#include "W2DRewriter.h"
-#include "UnicodeString.h"
-#include "SLDSymbols.h"
+#define ROUND(x) (int)((x) + 0.5)
+
+// maximum allowed size for images
+#define IMAGE_SIZE_MAX 2048.0*2048.0
+
+
//table we use for keeping track of object nodes
typedef DWFWCharKeySkipList<unsigned int> NodeTable;
@@ -708,7 +718,7 @@
m_imgID++,
NULL,
length,
- (WT_Byte*)data,
+ data,
WT_Logical_Point(x0, y0),
WT_Logical_Point(x1, y1),
false);
@@ -724,7 +734,7 @@
m_imgID++,
NULL,
length,
- (WT_Byte*)data,
+ data,
WT_Logical_Point(x0, y0),
WT_Logical_Point(x1, y1),
false);
@@ -2211,7 +2221,9 @@
double h,
double angledeg)
{
- if (format != RS_ImageFormat_RGBA && format != RS_ImageFormat_PNG)
+ if (format != RS_ImageFormat_RGB &&
+ format != RS_ImageFormat_RGBA &&
+ format != RS_ImageFormat_PNG)
{
//TODO: support other formats...
_ASSERT(false);
@@ -2221,42 +2233,142 @@
// draw to the active file if it's set
WT_File* file = m_w2dActive? m_w2dActive : m_w2dFile;
- WT_Integer32 x0 = (WT_Integer32)(x - 0.5*w);
- WT_Integer32 y0 = (WT_Integer32)(y - 0.5*h);
- WT_Integer32 x1 = (WT_Integer32)(x + 0.5*w);
- WT_Integer32 y1 = (WT_Integer32)(y + 0.5*h);
+ // find the corners of the image
+ SE_Matrix xform;
+ xform.rotate(angledeg * M_PI180);
+ xform.translate(x, y);
- if (format == RS_ImageFormat_RGBA)
+ double ptsx[4], ptsy[4];
+ xform.transform(-0.5*w, -0.5*h, ptsx[0], ptsy[0]);
+ xform.transform( 0.5*w, -0.5*h, ptsx[1], ptsy[1]);
+ xform.transform( 0.5*w, 0.5*h, ptsx[2], ptsy[2]);
+ xform.transform(-0.5*w, 0.5*h, ptsx[3], ptsy[3]);
+
+ WT_Logical_Point dstpts[4];
+ for (int i=0; i<4; i++)
{
- WT_Image img((WT_Unsigned_Integer16)native_height,
- (WT_Unsigned_Integer16)native_width,
- WT_Image::RGBA,
- m_imgID++,
- NULL,
- length,
- (WT_Byte*)data,
- WT_Logical_Point(x0, y0),
- WT_Logical_Point(x1, y1),
- false);
+ dstpts[i].m_x = (WT_Integer32)ptsx[i];
+ dstpts[i].m_y = (WT_Integer32)ptsy[i];
+ }
- img.serialize(*file);
- ++m_drawableCount;
+ if (angledeg == 0.0)
+ {
+ // simple case of no rotation
+ if (format == RS_ImageFormat_RGB || format == RS_ImageFormat_RGBA)
+ {
+ WT_Image img((WT_Unsigned_Integer16)native_height,
+ (WT_Unsigned_Integer16)native_width,
+ (format == RS_ImageFormat_RGB)? WT_Image::RGB : WT_Image::RGBA,
+ m_imgID++,
+ NULL,
+ length,
+ data,
+ dstpts[0],
+ dstpts[2],
+ false);
+
+ img.serialize(*file);
+ ++m_drawableCount;
+ }
+ else if (format == RS_ImageFormat_PNG)
+ {
+ WT_PNG_Group4_Image img((WT_Unsigned_Integer16)native_height,
+ (WT_Unsigned_Integer16)native_width,
+ WT_PNG_Group4_Image::PNG,
+ m_imgID++,
+ NULL,
+ length,
+ data,
+ dstpts[0],
+ dstpts[2],
+ false);
+
+ img.serialize(*file);
+ ++m_drawableCount;
+ }
}
- else if (format == RS_ImageFormat_PNG)
+ else
{
- WT_PNG_Group4_Image img((WT_Unsigned_Integer16)native_height,
- (WT_Unsigned_Integer16)native_width,
- WT_PNG_Group4_Image::PNG,
- m_imgID++,
- NULL,
- length,
- (WT_Byte*)data,
- WT_Logical_Point(x0, y0),
- WT_Logical_Point(x1, y1),
- false);
+ // rotated case
+ if (format == RS_ImageFormat_RGB || format == RS_ImageFormat_RGBA)
+ {
+ RotateRGBAImage((WT_Unsigned_Integer16)native_height,
+ (WT_Unsigned_Integer16)native_width,
+ (format == RS_ImageFormat_RGB)? WT_Image::RGB : WT_Image::RGBA,
+ NULL,
+ data,
+ m_imgID++,
+ dstpts,
+ *file);
+ ++m_drawableCount;
+ }
+ else if (format == RS_ImageFormat_PNG)
+ {
+ // compute the scaled size
+ double screenPixelsPerW2D = m_dpi / 25.4 / GetPixelsPerMillimeterScreen();
+ double scaledW = w * screenPixelsPerW2D;
+ double scaledH = h * screenPixelsPerW2D;
- img.serialize(*file);
- ++m_drawableCount;
+ // don't allow images beyond the maximum size
+ if (scaledW * scaledH > IMAGE_SIZE_MAX)
+ return;
+
+ // compute the rotated size
+ double minx = rs_min(ptsx[0], rs_min(ptsx[1], rs_min(ptsx[2], ptsx[3])));
+ double maxx = rs_max(ptsx[0], rs_max(ptsx[1], rs_max(ptsx[2], ptsx[3])));
+ double miny = rs_min(ptsy[0], rs_min(ptsy[1], rs_min(ptsy[2], ptsy[3])));
+ double maxy = rs_max(ptsy[0], rs_max(ptsy[1], rs_max(ptsy[2], ptsy[3])));
+ double rotatedW = (maxx - minx) * screenPixelsPerW2D;
+ double rotatedH = (maxy - miny) * screenPixelsPerW2D;
+
+ // don't allow images beyond the maximum size
+ if (rotatedW * rotatedH > IMAGE_SIZE_MAX)
+ return;
+
+ // load the source image
+ gdImagePtr src = gdImageCreateFromPngPtr(length, data);
+
+ // scale it if necessary
+ if ((int)scaledW != gdImageSX(src) || (int)scaledH != gdImageSY(src))
+ {
+ gdImagePtr dst = gdImageCreateTrueColor((int)scaledW, (int)scaledH);
+ gdImageAlphaBlending(dst, 0);
+ gdImageFilledRectangle(dst, 0, 0, gdImageSX(dst)-1, gdImageSY(dst)-1, 0x7f000000);
+ gdImageAlphaBlending(dst, 1);
+ gdImageCopyResampled(dst, src, 0, 0, 0, 0, gdImageSX(dst), gdImageSY(dst), gdImageSX(src), gdImageSY(src));
+ gdImageDestroy(src);
+ src = dst;
+ }
+
+ // rotate the image
+ gdImagePtr dst = gdImageCreateTrueColor((int)rotatedW, (int)rotatedH);
+ gdImageAlphaBlending(dst, 0);
+ gdImageFilledRectangle(dst, 0, 0, gdImageSX(dst)-1, gdImageSY(dst)-1, 0x7f000000);
+ gdImageAlphaBlending(dst, 1);
+ gdImageCopyRotated(dst, src, 0.5*rotatedW, 0.5*rotatedH, 0, 0, gdImageSX(src), gdImageSY(src), (int)ROUND(angledeg));
+ gdImageSaveAlpha(dst, 1);
+
+ // create the DWF image from the PNG data
+ int pngSize = 0;
+ unsigned char* pngData = (unsigned char*)gdImagePngPtr(dst, &pngSize);
+
+ WT_PNG_Group4_Image img((WT_Unsigned_Integer16)gdImageSY(dst),
+ (WT_Unsigned_Integer16)gdImageSX(dst),
+ WT_PNG_Group4_Image::PNG,
+ m_imgID++,
+ NULL,
+ pngSize,
+ pngData,
+ WT_Logical_Point((WT_Integer32)minx, (WT_Integer32)miny),
+ WT_Logical_Point((WT_Integer32)maxx, (WT_Integer32)maxy),
+ false);
+ img.serialize(*file);
+ ++m_drawableCount;
+
+ gdFree(pngData);
+ gdImageDestroy(dst);
+ gdImageDestroy(src);
+ }
}
}
Modified: trunk/MgDev/Common/Stylization/GDRenderer.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/GDRenderer.cpp 2007-03-27 00:23:56 UTC (rev 1379)
+++ trunk/MgDev/Common/Stylization/GDRenderer.cpp 2007-03-27 16:13:32 UTC (rev 1380)
@@ -147,7 +147,7 @@
// initialize the image to the supplied color (temporarily turn
// off alpha blending so the fill has the supplied alpha)
gdImageAlphaBlending(img, 0);
- gdImageFilledRectangle(img, 0, 0, gdImageSX(img)-1, gdImageSY(img), bgc);
+ gdImageFilledRectangle(img, 0, 0, gdImageSX(img)-1, gdImageSY(img)-1, bgc);
gdImageAlphaBlending(img, 1);
// set any transparent color
@@ -237,13 +237,13 @@
// initialize the destination image to the bg color (temporarily turn
// off alpha blending so the fill has the supplied alpha)
gdImageAlphaBlending(im, 0);
- gdImageFilledRectangle(im, 0, 0, gdImageSX(im)-1, gdImageSY(im), bgc);
+ gdImageFilledRectangle(im, 0, 0, gdImageSX(im)-1, gdImageSY(im)-1, bgc);
// set any transparent color
if (m_bgcolor.alpha() != 255)
gdImageColorTransparent(im, bgc);
- gdImageCopyResized(im, (gdImagePtr)m_imout, 0, 0, 0,0,width, height, m_width, m_height);
+ gdImageCopyResized(im, (gdImagePtr)m_imout, 0, 0, 0, 0, width, height, m_width, m_height);
gdImageAlphaBlending(im, 1);
}
else
@@ -774,18 +774,18 @@
}
// initialize the temporary supersampled symbol image to a transparent background
- gdImageAlphaBlending((gdImagePtr)tmp, 0);
- gdImageFilledRectangle((gdImagePtr)tmp, 0, 0, gdImageSX((gdImagePtr)tmp)-1, gdImageSY((gdImagePtr)tmp), 0x7f000000);
- gdImageAlphaBlending((gdImagePtr)tmp, 1);
+ gdImageAlphaBlending(tmp, 0);
+ gdImageFilledRectangle(tmp, 0, 0, gdImageSX(tmp)-1, gdImageSY(tmp)-1, 0x7f000000);
+ gdImageAlphaBlending(tmp, 1);
if (!nm)
{
//unknown symbol or symbol library error
RS_Color red(255, 0, 0, 255);
gdImagePtr brush1 = rs_gdImageThickLineBrush(rs_min(superw, superh) / 17, red);
- gdImageSetBrush((gdImagePtr)tmp, brush1);
+ gdImageSetBrush(tmp, brush1);
- gdImageOpenPolygon((gdImagePtr)tmp, (gdPointPtr)pts, npts, gdBrushed);
+ gdImageOpenPolygon(tmp, (gdPointPtr)pts, npts, gdBrushed);
gdImageSetBrush(tmp, NULL);
gdImageDestroy(brush1);
@@ -795,14 +795,14 @@
//draw fill
// TODO: When a filled polygon image is down-sampled, a gray false edge is created.
// This edge can only be seen when the real edge is not being drawn.
- gdImageFilledPolygon((gdImagePtr)tmp, (gdPointPtr)pts, npts, gdcfill);
+ gdImageFilledPolygon(tmp, (gdPointPtr)pts, npts, gdcfill);
//draw outline with a thickness set so that when scaled down to
//th destination image, the outline is still fully visible
gdImagePtr brush1 = rs_gdImageThickLineBrush(rs_min(superw, superh) / 17, outline);
- gdImageSetBrush((gdImagePtr)tmp, brush1);
+ gdImageSetBrush(tmp, brush1);
- gdImageOpenPolygon((gdImagePtr)tmp, (gdPointPtr)pts, npts, gdBrushed);
+ gdImageOpenPolygon(tmp, (gdPointPtr)pts, npts, gdBrushed);
gdImageSetBrush(tmp, NULL);
gdImageDestroy(brush1);
@@ -810,7 +810,7 @@
// initialize the real cached symbol image to a transparent background
gdImageAlphaBlending((gdImagePtr)m_imsym, 0);
- gdImageFilledRectangle((gdImagePtr)m_imsym, 0, 0, gdImageSX((gdImagePtr)m_imsym)-1, gdImageSY((gdImagePtr)m_imsym), 0x7f000000);
+ gdImageFilledRectangle((gdImagePtr)m_imsym, 0, 0, gdImageSX((gdImagePtr)m_imsym)-1, gdImageSY((gdImagePtr)m_imsym)-1, 0x7f000000);
gdImageAlphaBlending((gdImagePtr)m_imsym, 1);
//resample the supersampled temporary image into the cached image
@@ -892,7 +892,7 @@
// initialize the temporary symbol image to a transparent background
gdImageAlphaBlending((gdImagePtr)m_imsym, 0);
- gdImageFilledRectangle((gdImagePtr)m_imsym, 0, 0, gdImageSX((gdImagePtr)m_imsym)-1, gdImageSY((gdImagePtr)m_imsym), 0x7f000000);
+ gdImageFilledRectangle((gdImagePtr)m_imsym, 0, 0, gdImageSX((gdImagePtr)m_imsym)-1, gdImageSY((gdImagePtr)m_imsym)-1, 0x7f000000);
gdImageAlphaBlending((gdImagePtr)m_imsym, 1);
}
else
@@ -958,19 +958,18 @@
//straight copy without resampling since we are
//guaranteed for the source image size to equal the
//symbol pixel size
- gdImageCopy((gdImagePtr)m_imout, (gdImagePtr)m_imsym,
- ulx, uly, 0, 0, imsymw, imsymh);
+ gdImageCopy((gdImagePtr)m_imout, (gdImagePtr)m_imsym, ulx, uly, 0, 0, imsymw, imsymh);
}
else
{
//for rotated copy, we need to scale down the image first
//allocating an extra image here should not be too much of
//an overhead since it is usually small
- gdImagePtr tmp = gdImageCreateTrueColor(imsymw + 2, imsymh + 2);
+ gdImagePtr tmp = gdImageCreateTrueColor(imsymw+2, imsymh+2);
//make it transparent
gdImageAlphaBlending(tmp, 0);
- gdImageFilledRectangle(tmp, 0, 0, imsymw + 1, imsymh + 2, 0x7f000000);
+ gdImageFilledRectangle(tmp, 0, 0, imsymw+1, imsymh+1, 0x7f000000);
gdImageAlphaBlending(tmp, 1);
//straight copy without resampling since we are
@@ -984,9 +983,7 @@
int my = (int)floor(0.5 * (b[0].y + b[2].y));
//draw rotated symbol onto final destination image
- gdImageCopyRotated((gdImagePtr)m_imout, (gdImagePtr)tmp,
- mx, my, 0, 0, imsymw + 2, imsymh + 2,
- (int)(mdef.rotation()));
+ gdImageCopyRotated((gdImagePtr)m_imout, tmp, mx, my, 0, 0, imsymw+2, imsymh+2, (int)ROUND(mdef.rotation()));
gdImageDestroy(tmp);
}
@@ -2357,7 +2354,7 @@
//TODO: must scale from native width/height to requested width/height
gdImageCopyRotated((gdImagePtr)m_imout, src,
- x, y, 0, 0, native_width, native_height, (int)angledeg);
+ x, y, 0, 0, native_width, native_height, (int)ROUND(angledeg));
}
gdImageDestroy(src);
@@ -2389,7 +2386,7 @@
//TODO: must scale from native width/height to requested width/height
gdImageCopyRotated((gdImagePtr)m_imout, src,
- x, y, 0, 0, gdImageSX(src), gdImageSY(src), (int)angledeg);
+ x, y, 0, 0, gdImageSX(src), gdImageSY(src), (int)ROUND(angledeg));
}
gdImageDestroy(src);
Modified: trunk/MgDev/Common/Stylization/GDUtils.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/GDUtils.cpp 2007-03-27 00:23:56 UTC (rev 1379)
+++ trunk/MgDev/Common/Stylization/GDUtils.cpp 2007-03-27 16:13:32 UTC (rev 1380)
@@ -55,19 +55,17 @@
gdImagePtr rs_gdImageThickLineBrush(int line_weight, RS_Color& color)
{
- gdImagePtr brush1 = NULL;
-
if (line_weight % 2 == 1)
line_weight += 1;
int sx = line_weight;
int sy = line_weight;
- brush1 = gdImageCreateTrueColor(sx, sy);
- int transparent = gdImageColorAllocateAlpha(brush1, 0, 0, 0, 127);
+ gdImagePtr brush = gdImageCreateTrueColor(sx, sy);
+ int transparent = gdImageColorAllocateAlpha(brush, 0, 0, 0, 127);
- gdImageAlphaBlending(brush1, 0);
- gdImageFilledRectangle(brush1, 0, 0, sx, sy, transparent);
+ gdImageAlphaBlending(brush, 0);
+ gdImageFilledRectangle(brush, 0, 0, sx, sy, transparent);
//compute fractional alpha value for antialiasing effect
//each pixel should be hit by line_weight / 2 number of circles
@@ -77,12 +75,12 @@
falpha.alpha() = (falpha.alpha() < 255)? falpha.alpha() : 255;
//outer transparent circle -- for antialiased effect
- rs_gdImageCircleForBrush(brush1, sx/2, sy/2, line_weight / 2, falpha);
+ rs_gdImageCircleForBrush(brush, sx/2, sy/2, line_weight / 2, falpha);
- gdImageAlphaBlending(brush1, 1);
+ gdImageAlphaBlending(brush, 1);
//inner non-transparent circle
- rs_gdImageCircleForBrush(brush1, sx/2, sy/2, (line_weight - 2) / 2, color);
+ rs_gdImageCircleForBrush(brush, sx/2, sy/2, (line_weight - 2) / 2, color);
- return brush1;
+ return brush;
}
Modified: trunk/MgDev/Common/Stylization/GDW2DRewriter.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/GDW2DRewriter.cpp 2007-03-27 00:23:56 UTC (rev 1379)
+++ trunk/MgDev/Common/Stylization/GDW2DRewriter.cpp 2007-03-27 16:13:32 UTC (rev 1380)
@@ -350,29 +350,28 @@
//make it transparent
gdImageAlphaBlending(resized, 0);
- gdImageFilledRectangle(resized, 0, 0, width-1, height, 0x7f000000);
+ gdImageFilledRectangle(resized, 0, 0, width-1, height-1, 0x7f000000);
gdImageAlphaBlending(resized, 1);
gdImageCopyResampled(resized, src,
- 0, 0, //dstX, dstY
- 0, 0, //srcX, srcY
- width, height, //int dstW, int dstH,
- src->sx, src->sy );//srcW, srcH
+ 0, 0, //dstX, dstY
+ 0, 0, //srcX, srcY
+ width, height, //dstW, dstH,
+ src->sx, src->sy ); //srcW, srcH
}
double midx = 0.5 * (dstpts[0].x + dstpts[2].x);
double midy = 0.5 * (dstpts[0].y + dstpts[2].y);
- double angle = atan2((double)(dstpts[1].y - dstpts[0].y), (double)(dstpts[1].x - dstpts[0].x));
+ double anglerad = atan2((double)(dstpts[1].y - dstpts[0].y), (double)(dstpts[1].x - dstpts[0].x));
gdImageCopyRotated ((gdImagePtr)rewriter->GetW2DTargetImage(),
- resized ? resized : src,
+ resized? resized : src,
midx, midy, //dstX, dstY
0, 0, //srcX, srcY
- resized ? resized->sx : src->sx,
- resized ? resized->sx : src->sy, //srcW, srcH
- (int)(-angle / M_PI180)
- );
+ resized? resized->sx : src->sx,
+ resized? resized->sx : src->sy, //srcW, srcH
+ (int)ROUND(-anglerad / M_PI180));
if (resized)
gdImageDestroy(resized);
@@ -703,16 +702,15 @@
double midx = 0.5 * (dstpts[0].x + dstpts[2].x);
double midy = 0.5 * (dstpts[0].y + dstpts[2].y);
- double angle = atan2((double)(dstpts[1].y - dstpts[0].y), (double)(dstpts[1].x - dstpts[0].x));
+ double anglerad = atan2((double)(dstpts[1].y - dstpts[0].y), (double)(dstpts[1].x - dstpts[0].x));
gdImageCopyRotated ((gdImagePtr)rewriter->GetW2DTargetImage(),
- resized ? resized : src,
+ resized? resized : src,
midx, midy, //dstX, dstY
0, 0, //srcX, srcY
- resized ? resized->sx : src->sx,
- resized ? resized->sx : src->sy, //srcW, srcH
- (int)(-angle / M_PI180)
- );
+ resized? resized->sx : src->sx,
+ resized? resized->sx : src->sy, //srcW, srcH
+ (int)ROUND(-anglerad / M_PI180));
if (resized)
gdImageDestroy(resized);
Modified: trunk/MgDev/Common/Stylization/W2DRewriter.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/W2DRewriter.cpp 2007-03-27 00:23:56 UTC (rev 1379)
+++ trunk/MgDev/Common/Stylization/W2DRewriter.cpp 2007-03-27 16:13:32 UTC (rev 1380)
@@ -562,291 +562,303 @@
return WT_Result::Success;
}
-int g_imageId = 1;//TODO: may be this should be a variable in DWFRenderer
-WT_Result simple_process_image (WT_Image & image, WT_File & file)
+void RotateRGBAImage(const WT_Unsigned_Integer16 rows,
+ const WT_Unsigned_Integer16 columns,
+ const WT_Image::WT_Image_Format format,
+ const WT_Color_Map* color_map,
+ const WT_Byte* data,
+ const WT_Integer32 identifier,
+ const WT_Logical_Point* dstpts,
+ WT_File & file)
{
- DWFRenderer* rewriter = (DWFRenderer*)file.stream_user_data();
+ // The difficult case when it is rotated -- make a new image which
+ // encompasses the rotated extent. We also have to use RGBA format
+ // since we need the pieces which are in the bigger axis-aligned
+ // bitmap but not overlapped by the rotated image to be transparent.
- if (!rewriter->LayerPassesFilter())
- return WT_Result::Success;
+ //find new bounds for image -> basically axis-aligned bounds of
+ //the rotated initial image bounds
+ WT_Integer32 minx = rs_min(dstpts[0].m_x, rs_min(dstpts[1].m_x, rs_min(dstpts[2].m_x, dstpts[3].m_x)));
+ WT_Integer32 maxx = rs_max(dstpts[0].m_x, rs_max(dstpts[1].m_x, rs_max(dstpts[2].m_x, dstpts[3].m_x)));
- //transform the bounds
- WT_Logical_Box bounds = image.bounds();
+ WT_Integer32 miny = rs_min(dstpts[0].m_y, rs_min(dstpts[1].m_y, rs_min(dstpts[2].m_y, dstpts[3].m_y)));
+ WT_Integer32 maxy = rs_max(dstpts[0].m_y, rs_max(dstpts[1].m_y, rs_max(dstpts[2].m_y, dstpts[3].m_y)));
- WT_Logical_Point endpts[4];
- endpts[0].m_x = bounds.m_min.m_x;
- endpts[0].m_y = bounds.m_min.m_y;
- endpts[1].m_x = bounds.m_max.m_x;
- endpts[1].m_y = bounds.m_min.m_y;
- endpts[2].m_x = bounds.m_max.m_x;
- endpts[2].m_y = bounds.m_max.m_y;
- endpts[3].m_x = bounds.m_min.m_x;
- endpts[3].m_y = bounds.m_max.m_y;
+ WT_Integer32 width = maxx - minx /*??+ 1*/;
+ WT_Integer32 height = maxy - miny /*??+ 1*/;
- int numpts = 0;
- std::vector<int>* cntrs = NULL;
- const WT_Logical_Point* dstpts = rewriter->ProcessW2DPoints(
- file, endpts, 4, LineBuffer::ctPoint, numpts, &cntrs);
+ //get basis vectors of transformed space
+ double e1x = dstpts[1].m_x - dstpts[0].m_x;
+ double e1y = dstpts[1].m_y - dstpts[0].m_y;
+ double e2x = dstpts[3].m_x - dstpts[0].m_x;
+ double e2y = dstpts[3].m_y - dstpts[0].m_y;
- if (numpts == 4)
- {
- //check for rotation -- DWF does not support rotated images, so we need to
- //do it manually.
+ //find width and height if image were not rotated (but just scaled)
+ double nonrot_width = sqrt(e1x*e1x + e1y*e1y);
+ double nonrot_height = sqrt(e2x*e2x + e2y*e2y);
- if ( dstpts[0].m_y == dstpts[1].m_y
- && dstpts[1].m_x == dstpts[2].m_x)
- {
- //case of no rotation -- direct copy of the image
- WT_Image image2(
- image.rows(),
- image.columns(),
- WT_Image::WT_Image_Format(image.format()),
- g_imageId++,
- image.color_map(),
- image.data_size(),
- (WT_Byte*)image.data(),
- dstpts[0], //min pt
- dstpts[2], //max pt
- true);
+ //normalize basis vectors
+ e1x /= nonrot_width;
+ e1y /= nonrot_width;
+ e2x /= nonrot_height;
+ e2y /= nonrot_height;
- image2.serialize(*rewriter->_GetW2D());
- }
- else if ( image.format() == WT_Image::RGB
- || image.format() == WT_Image::RGBA)
- {
- //the difficult case when it is rotated -- make a new image
- //which encompasses the rotated extent -- also since we need
- //the pieces which are in the bigger axis aligned bitmap but not
- //overlapped by the rotated image to be transparent, so we have to use RGBA
- //format.
+ //determine size of new image in pixels
+ double inv_old_cols = (double)columns / nonrot_width;
+ double inv_old_rows = (double)rows / nonrot_height;
+ int new_cols = (int)((double)width * inv_old_cols);
+ int new_rows = (int)((double)height * inv_old_rows);
- //find new bounds for image -> basically axis-aligned bounds of
- //the rotated initial image bounds
- WT_Integer32 minx = rs_min(dstpts[0].m_x, rs_min(dstpts[1].m_x, rs_min(dstpts[2].m_x, dstpts[3].m_x)));
- WT_Integer32 maxx = rs_max(dstpts[0].m_x, rs_max(dstpts[1].m_x, rs_max(dstpts[2].m_x, dstpts[3].m_x)));
+ //alloc mem for image
+ int len = new_cols * new_rows;
+ WT_RGBA32* pixels = new WT_RGBA32[new_cols * new_rows];
- WT_Integer32 miny = rs_min(dstpts[0].m_y, rs_min(dstpts[1].m_y, rs_min(dstpts[2].m_y, dstpts[3].m_y)));
- WT_Integer32 maxy = rs_max(dstpts[0].m_y, rs_max(dstpts[1].m_y, rs_max(dstpts[2].m_y, dstpts[3].m_y)));
+ //initialize to transparent color
+ memset(pixels, 0, sizeof(WT_RGBA32)*len);
- WT_Integer32 width = maxx - minx /*??+ 1*/;
- WT_Integer32 height = maxy - miny /*??+ 1*/;
+ //loop invariants
+ double inv_new_cols = (double)width / new_cols;
+ double inv_new_rows = (double)height/ new_rows;
+ int old_rows = rows;
+ int old_cols = columns;
- //get basis vectors of transformed space
- double e1x = dstpts[1].m_x - dstpts[0].m_x;
- double e1y = dstpts[1].m_y - dstpts[0].m_y;
- double e2x = dstpts[3].m_x - dstpts[0].m_x;
- double e2y = dstpts[3].m_y - dstpts[0].m_y;
+ for (int j=0; j<new_rows; j++)
+ {
+ for (int i=0; i<new_cols; i++)
+ {
+ //compute W2D logical location of pixel
+ double dstx = i * (inv_new_cols) + minx;
+ double dsty = (new_rows - 1 -j) * (inv_new_rows) + miny;
- //find width and height if image were not rotated (but just scaled)
- double nonrot_width = sqrt(e1x*e1x + e1y*e1y);
- double nonrot_height = sqrt(e2x*e2x + e2y*e2y);
+ //convert location to a location vector
+ //from origin of non-rotated image
+ double ddx = dstx - dstpts[0].m_x;
+ double ddy = dsty - dstpts[0].m_y;
- //normalize basis vectors
- e1x /= nonrot_width;
- e1y /= nonrot_width;
- e2x /= nonrot_height;
- e2y /= nonrot_height;
+ //project vector onto rotated basis vectors
+ double dote1 = e1x * ddx + e1y * ddy;
+ double dote2 = e2x * ddx + e2y * ddy;
- //determine size of new image in pixels
- double inv_old_cols = (double)image.columns() / nonrot_width;
- double inv_old_rows = (double)image.rows() / nonrot_height;
- int new_cols = (int)((double)width * inv_old_cols);
- int new_rows = (int)((double)height * inv_old_rows);
+ //convert projected values to pixel coordinates
+ //inside the source image
+ double pixelx = dote1 * inv_old_cols;
+ double pixely = old_rows - dote2 * inv_old_rows;
- //alloc mem for image
- int len = new_cols * new_rows;
- WT_RGBA32* pixels = new WT_RGBA32[new_cols * new_rows];
+ //if the pixel coordinates are inside the source
+ //image we will obtain an interpolated color
+ //for the destination image
+ if (pixelx >=-1 && pixelx <= old_cols &&
+ pixely >=-1 && pixely <= old_rows)
+ {
+ int xwhole = (int)floor(pixelx);
+ int ywhole = (int)floor(pixely);
- //initialize to transparent color
- memset(pixels, 0, sizeof(WT_RGBA32)*len);
+ //4 nearest pixels
+ WT_RGBA32 c00(0,0,0,0);
+ WT_RGBA32 c10(0,0,0,0);
+ WT_RGBA32 c11(0,0,0,0);
+ WT_RGBA32 c01(0,0,0,0);
- //loop invariants
- double inv_new_cols = (double)width / new_cols;
- double inv_new_rows = (double)height/ new_rows;
- int format = image.format();
- const WT_Byte* data = image.data();
- int old_rows = image.rows();
- int old_cols = image.columns();
-
- for (int j=0; j<new_rows; j++)
- {
- for (int i=0; i<new_cols; i++)
+ //get values for the 4 nearest pixels, taking care
+ //not to go overboard (outside the image)
+ switch (format)
{
- //compute W2D logical location of pixel
- double dstx = i * (inv_new_cols) + minx;
- double dsty = (new_rows - 1 -j) * (inv_new_rows) + miny;
+ case WT_Image::RGBA:
+ if (pixelx >= 0)
+ {
+ if (pixely >=0)
+ c00 = ((WT_RGBA32*)data)[xwhole + ywhole * old_cols];
- //convert location to a location vector
- //from origin of non-rotated image
- double ddx = dstx - dstpts[0].m_x;
- double ddy = dsty - dstpts[0].m_y;
+ if (pixely < old_rows - 1)
+ c01 = ((WT_RGBA32*)data)[xwhole + (ywhole + 1) * old_cols];
+ }
- //project vector onto rotated basis vectors
- double dote1 = e1x * ddx + e1y * ddy;
- double dote2 = e2x * ddx + e2y * ddy;
+ if (pixelx < old_cols - 1)
+ {
+ if (pixely >=0)
+ c10 = ((WT_RGBA32*)data)[xwhole + 1 + ywhole * old_cols];
- //convert projected values to pixel coordinates
- //inside the source image
- double pixelx = dote1 * inv_old_cols;
- double pixely = old_rows - dote2 * inv_old_rows;
-
- //if the pixel coordinates are inside the source
- //image we will obtain an interpolated color
- //for the destination image
- if (pixelx >=-1 && pixelx <= old_cols
- && pixely >=-1 && pixely <= old_rows)
+ if (pixely < old_rows - 1)
+ c11 = ((WT_RGBA32*)data)[xwhole + 1 + (ywhole + 1) * old_cols];
+ }
+ break;
+ case WT_Image::RGB:
{
- int xwhole = (int)floor(pixelx);
- int ywhole = (int)floor(pixely);
+ const WT_Byte* ptr = NULL;
- //4 nearest pixels
- WT_RGBA32 c00(0,0,0,0);
- WT_RGBA32 c10(0,0,0,0);
- WT_RGBA32 c11(0,0,0,0);
- WT_RGBA32 c01(0,0,0,0);
-
- //get values for the 4 nearesr pixels, taking care
- //not to go overboard (outside the image)
- switch (format)
+ if (pixelx >= 0)
{
- case WT_Image::RGBA:
- if (pixelx >= 0)
+ if (pixely >= 0)
{
- if (pixely >=0)
- c00 = ((WT_RGBA32*)data)[xwhole + ywhole * old_cols];
+ ptr = data + 3*(xwhole + ywhole * old_cols);
+ c00.m_rgb.b = *ptr++;
+ c00.m_rgb.g = *ptr++;
+ c00.m_rgb.r = *ptr++;
+ c00.m_rgb.a = 255;
+ }
- if (pixely < old_rows - 1)
- c01 = ((WT_RGBA32*)data)[xwhole + (ywhole + 1) * old_cols];
+ if (pixely < old_rows - 1)
+ {
+ ptr = data + 3*(xwhole + (ywhole + 1) * old_cols);
+ c01.m_rgb.b = *ptr++;
+ c01.m_rgb.g = *ptr++;
+ c01.m_rgb.r = *ptr++;
+ c01.m_rgb.a = 255;
}
+ }
- if (pixelx < old_cols - 1)
+ if (pixelx < old_cols - 1)
+ {
+ ptr = data + 3*(xwhole + 1 + ywhole * old_cols);
+
+ if (pixely >= 0)
{
- if (pixely >=0)
- c10 = ((WT_RGBA32*)data)[xwhole + 1 + ywhole * old_cols];
+ c10.m_rgb.b = *ptr++;
+ c10.m_rgb.g = *ptr++;
+ c10.m_rgb.r = *ptr++;
+ c10.m_rgb.a = 255;
+ }
- if (pixely < old_rows - 1)
- c11 = ((WT_RGBA32*)data)[xwhole + 1 + (ywhole + 1) * old_cols];
+ if (pixely < old_rows - 1)
+ {
+ ptr = data + 3*(xwhole + 1 + (ywhole + 1) * old_cols);
+ c11.m_rgb.b = *ptr++;
+ c11.m_rgb.g = *ptr++;
+ c11.m_rgb.r = *ptr++;
+ c11.m_rgb.a = 255;
}
- break;
- case WT_Image::RGB:
- {
- const WT_Byte* ptr = NULL;
+ }
+ }
+ break;
+ }
- if (pixelx >= 0)
- {
- if (pixely >= 0)
- {
- ptr = data + 3*(xwhole + ywhole * old_cols);
- c00.m_rgb.b = *ptr++;
- c00.m_rgb.g = *ptr++;
- c00.m_rgb.r = *ptr++;
- c00.m_rgb.a = 255;
- }
+ //bilinear interpolation of nearest pixels
+ float ifx = (float)(pixelx - xwhole);
+ float ify = (float)(pixely - ywhole);
+ float fx = 1.0f - ifx;
+ float fy = 1.0f - ify;
+ float fxfy = fx * fy;
+ float ifxfy = ifx * fy;
+ float ifxify = ifx * ify;
+ float fxify = fx * ify;
- if (pixely < old_rows - 1)
- {
- ptr = data + 3*(xwhole + (ywhole + 1) * old_cols);
- c01.m_rgb.b = *ptr++;
- c01.m_rgb.g = *ptr++;
- c01.m_rgb.r = *ptr++;
- c01.m_rgb.a = 255;
- }
- }
+ float c00a = fxfy * (float)c00.m_rgb.a / 255.0f;
+ float c10a = ifxfy * (float)c10.m_rgb.a / 255.0f;
+ float c11a = ifxify * (float)c11.m_rgb.a / 255.0f;
+ float c01a = fxify * (float)c01.m_rgb.a / 255.0f;
- if (pixelx < old_cols - 1)
- {
- ptr = data + 3*(xwhole + 1 + ywhole * old_cols);
+ float a_normalize = (float)(1.0f / (c00a + c10a + c11a + c01a));
- if (pixely >= 0)
- {
- c10.m_rgb.b = *ptr++;
- c10.m_rgb.g = *ptr++;
- c10.m_rgb.r = *ptr++;
- c10.m_rgb.a = 255;
- }
+ c00a *= a_normalize;
+ c10a *= a_normalize;
+ c11a *= a_normalize;
+ c01a *= a_normalize;
- if (pixely < old_rows - 1)
- {
- ptr = data + 3*(xwhole + 1 + (ywhole + 1) * old_cols);
- c11.m_rgb.b = *ptr++;
- c11.m_rgb.g = *ptr++;
- c11.m_rgb.r = *ptr++;
- c11.m_rgb.a = 255;
- }
- }
- }
- break;
- }
+ float red = c00a * c00.m_rgb.r
+ + c10a * c10.m_rgb.r
+ + c11a * c11.m_rgb.r
+ + c01a * c01.m_rgb.r;
- //bilinear interpolation of nearest pixels
- float ifx = (float)(pixelx - xwhole);
- float ify = (float)(pixely - ywhole);
- float fx = 1.0f - ifx;
- float fy = 1.0f - ify;
- float fxfy = fx * fy;
- float ifxfy = ifx * fy;
- float ifxify = ifx * ify;
- float fxify = fx * ify;
+ float green = c00a * c00.m_rgb.g
+ + c10a * c10.m_rgb.g
+ + c11a * c11.m_rgb.g
+ + c01a * c01.m_rgb.g;
- float c00a = fxfy * (float)c00.m_rgb.a / 255.0f;
- float c10a = ifxfy * (float)c10.m_rgb.a / 255.0f;
- float c11a = ifxify * (float)c11.m_rgb.a / 255.0f;
- float c01a = fxify * (float)c01.m_rgb.a / 255.0f;
+ float blue = c00a * c00.m_rgb.b
+ + c10a * c10.m_rgb.b
+ + c11a * c11.m_rgb.b
+ + c01a * c01.m_rgb.b;
- float a_normalize = (float)(1.0f / (c00a + c10a + c11a + c01a));
+ float alpha = fxfy * c00.m_rgb.a
+ + ifxfy * c10.m_rgb.a
+ + ifxify* c11.m_rgb.a
+ + fxify * c01.m_rgb.a;
- c00a *= a_normalize;
- c10a *= a_normalize;
- c11a *= a_normalize;
- c01a *= a_normalize;
+ WT_RGBA32 bilerp_col((int)(red+0.5f) & 0xFF, (int)(green+0.5f) & 0xFF, (int)(blue+0.5) & 0xFF, (int)(alpha+0.5f) & 0xFF);
+ pixels[i + new_cols * j] = bilerp_col;
+ }
+ }
+ }
- float red = c00a * c00.m_rgb.r
- + c10a * c10.m_rgb.r
- + c11a * c11.m_rgb.r
- + c01a * c01.m_rgb.r;
+ //make a new image out of the rotated data and send it to W2D
+ WT_Image image((WT_Unsigned_Integer16)new_rows,
+ (WT_Unsigned_Integer16)new_cols,
+ WT_Image::RGBA,
+ identifier,
+ color_map,
+ len * sizeof(WT_RGBA32),
+ (WT_Byte*)pixels,
+ WT_Logical_Point(minx, miny),
+ WT_Logical_Point(maxx, maxy),
+ true);
- float green = c00a * c00.m_rgb.g
- + c10a * c10.m_rgb.g
- + c11a * c11.m_rgb.g
- + c01a * c01.m_rgb.g;
+ image.serialize(file);
- float blue = c00a * c00.m_rgb.b
- + c10a * c10.m_rgb.b
- + c11a * c11.m_rgb.b
- + c01a * c01.m_rgb.b;
+ delete [] pixels;
+}
- float alpha = fxfy * c00.m_rgb.a
- + ifxfy * c10.m_rgb.a
- + ifxify* c11.m_rgb.a
- + fxify * c01.m_rgb.a;
- WT_RGBA32 bilerp_col((int)(red+0.5f) & 0xFF, (int)(green+0.5f) & 0xFF, (int)(blue+0.5) & 0xFF, (int)(alpha+0.5f) & 0xFF);
- pixels[i + new_cols * j] = bilerp_col;
- }
- }
- }
+int g_imageId = 1;//TODO: may be this should be a variable in DWFRenderer
- WT_Logical_Point minpt(minx, miny);
- WT_Logical_Point maxpt(maxx, maxy);
+WT_Result simple_process_image (WT_Image & image, WT_File & file)
+{
+ DWFRenderer* rewriter = (DWFRenderer*)file.stream_user_data();
- //make a new image out of the rotated data and send it to W2D
+ if (!rewriter->LayerPassesFilter())
+ return WT_Result::Success;
+
+ //transform the bounds
+ WT_Logical_Box bounds = image.bounds();
+
+ WT_Logical_Point endpts[4];
+ endpts[0].m_x = bounds.m_min.m_x;
+ endpts[0].m_y = bounds.m_min.m_y;
+ endpts[1].m_x = bounds.m_max.m_x;
+ endpts[1].m_y = bounds.m_min.m_y;
+ endpts[2].m_x = bounds.m_max.m_x;
+ endpts[2].m_y = bounds.m_max.m_y;
+ endpts[3].m_x = bounds.m_min.m_x;
+ endpts[3].m_y = bounds.m_max.m_y;
+
+ int numpts = 0;
+ std::vector<int>* cntrs = NULL;
+ const WT_Logical_Point* dstpts = rewriter->ProcessW2DPoints(
+ file, endpts, 4, LineBuffer::ctPoint, numpts, &cntrs);
+
+ if (numpts == 4)
+ {
+ //check for rotation -- DWF does not support rotated images, so we need to
+ //do it manually.
+
+ if (dstpts[0].m_y == dstpts[1].m_y && dstpts[1].m_x == dstpts[2].m_x)
+ {
+ //case of no rotation -- direct copy of the image
WT_Image image2(
- (WT_Unsigned_Integer16)new_rows,
- (WT_Unsigned_Integer16)new_cols,
- WT_Image::RGBA,
+ image.rows(),
+ image.columns(),
+ WT_Image::WT_Image_Format(image.format()),
g_imageId++,
image.color_map(),
- len * sizeof(WT_RGBA32),
- (WT_Byte*)pixels,
- minpt, //min pt
- maxpt, //max pt
+ image.data_size(),
+ (WT_Byte*)image.data(),
+ dstpts[0], //min pt
+ dstpts[2], //max pt
true);
image2.serialize(*rewriter->_GetW2D());
-
- delete [] pixels;
}
+ else if (image.format() == WT_Image::RGB || image.format() == WT_Image::RGBA)
+ {
+ RotateRGBAImage(image.rows(),
+ image.columns(),
+ (WT_Image::WT_Image_Format)image.format(),
+ image.color_map(),
+ image.data(),
+ g_imageId++,
+ dstpts,
+ *rewriter->_GetW2D());
+ }
}
return WT_Result::Success;
@@ -1124,8 +1136,6 @@
//only transfer the raster if it is fully inside destination box
//TODO: otherwise we need to clip the raster itself
- WT_Logical_Box box2(dstpts[0], dstpts[1]);
-
// Create a new WT_Drawable with the updated bounds
WT_PNG_Group4_Image img2(pngGroup4Image.rows(),
pngGroup4Image.columns(),
Modified: trunk/MgDev/Common/Stylization/W2DRewriter.h
===================================================================
--- trunk/MgDev/Common/Stylization/W2DRewriter.h 2007-03-27 00:23:56 UTC (rev 1379)
+++ trunk/MgDev/Common/Stylization/W2DRewriter.h 2007-03-27 16:13:32 UTC (rev 1380)
@@ -15,6 +15,9 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
+#ifndef W2DREWRITER_H
+#define W2DREWRITER_H
+
#include "whiptk/whip_toolkit.h"
// Standard action routines.
@@ -23,6 +26,15 @@
WT_Result simple_read (WT_File & file, int desired_bytes, int &bytes_read, void * buffer);
WT_Result simple_seek (WT_File & file, int distance, int &amount_seeked);
+void RotateRGBAImage(const WT_Unsigned_Integer16 rows,
+ const WT_Unsigned_Integer16 columns,
+ const WT_Image::WT_Image_Format format,
+ const WT_Color_Map* color_map,
+ const WT_Byte* data,
+ const WT_Integer32 identifier,
+ const WT_Logical_Point* dstpts,
+ WT_File & file);
+
WT_Result simple_process_author (WT_Author & author, WT_File & file);
WT_Result simple_process_creator (WT_Creator & creator, WT_File & file);
WT_Result simple_process_created (WT_Creation_Time & created, WT_File & file);
@@ -93,3 +105,5 @@
WT_Result simple_process_fillPattern (WT_Fill_Pattern & fillPattern, WT_File & file);
WT_Result simple_process_DigitalSign (WT_SignData & digitalSing, WT_File & file);
WT_Result simple_process_dwf_header (WT_DWF_Header & dwf_header, WT_File & file);
+
+#endif
More information about the mapguide-commits
mailing list