00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "FilterDevice.h"
00021
00022 #include <math.h>
00023 #include <KoFilterChain.h>
00024 #include <kdebug.h>
00025
00026 #include "GfxState.h"
00027 #include "Link.h"
00028
00029 #include "FilterPage.h"
00030 #include "data.h"
00031 #include "dialog.h"
00032
00033
00034 namespace PDFImport
00035 {
00036
00037 Device::Device(Data &data)
00038 : _data(data), _fillColor(Qt::white), _strokeColor(Qt::black)
00039 {
00040 _pages.setAutoDelete(true);
00041 }
00042
00043 Device::~Device()
00044 {
00045 clear();
00046 }
00047
00048 void Device::clear()
00049 {
00050 _images.clear();
00051 }
00052
00053 void Device::init()
00054 {
00055
00056 const double maxH = _data.pageRect().bottom();
00057 const double maxR = _data.pageRect().right();
00058
00059 double maxHeaderBottom = 0;
00060 double minBodyTop = maxH;
00061 double minHeaderBodyDelta = maxH;
00062 double maxBodyBottom = 0;
00063 double minFooterTop = maxH;
00064 double minBodyFooterDelta = maxH;
00065 double minLeft = maxR;
00066 double maxRight = 0;
00067
00068 for (Page *page = _pages.first(); page; page = _pages.next()) {
00069 const DRect &hr = page->rects()[Header];
00070 const DRect &br = page->rects()[Body];
00071 const DRect &fr = page->rects()[Footer];
00072 if ( hr.isValid() ) {
00073 maxHeaderBottom = kMax(maxHeaderBottom, hr.bottom());
00074 if ( br.isValid() )
00075 minHeaderBodyDelta =
00076 kMin(minHeaderBodyDelta, br.top() - hr.bottom());
00077 minLeft = kMin(minLeft, hr.left());
00078 maxRight = kMax(maxRight, hr.right());
00079 }
00080 if ( fr.isValid() ) {
00081 minFooterTop = kMin(minFooterTop, fr.top());
00082 if ( br.isValid() )
00083 minBodyFooterDelta =
00084 kMin(minBodyFooterDelta, fr.top() - br.bottom());
00085 minLeft = kMin(minLeft, fr.left());
00086 maxRight = kMax(maxRight, fr.right());
00087 }
00088 if ( br.isValid() ) {
00089 minBodyTop = kMin(minBodyTop, br.top());
00090 maxBodyBottom = kMax(maxBodyBottom, br.bottom());
00091 minLeft = kMin(minLeft, br.left());
00092 maxRight = kMax(maxRight, br.right());
00093 }
00094 }
00095
00096
00097 double minTop = kMax(maxHeaderBottom+minHeaderBodyDelta, minBodyTop);
00098 double maxBottom = kMin(minFooterTop-minBodyFooterDelta, maxBodyBottom);
00099 for (Page *page = _pages.first(); page; page = _pages.next()) {
00100 DRect &r = page->rects()[Body];
00101 if ( r.top()>minTop ) r.setTop(minTop);
00102 if ( r.bottom()<maxBottom ) r.setBottom(maxBottom);
00103 }
00104
00105
00106 for (Page *page = _pages.first(); page; page = _pages.next()) {
00107 DRect &hr = page->rects()[Header];
00108 if ( hr.isValid() ) {
00109 if ( hr.left()>minLeft ) hr.setLeft(minLeft);
00110 if ( hr.right()<maxRight ) hr.setRight(maxRight);
00111 }
00112 DRect &fr = page->rects()[Footer];
00113 if ( fr.isValid() ) {
00114 if ( fr.left()>minLeft ) fr.setLeft(minLeft);
00115 if ( fr.right()<maxRight ) fr.setRight(maxRight);
00116 }
00117 }
00118 }
00119
00120
00121 void Device::dumpPage(uint i)
00122 {
00123 Page *page = _pages.at(i);
00124 _data.initPage(page->rects(), page->pictures);
00125 page->dump();
00126 }
00127
00128 void Device::startPage(int, GfxState *)
00129 {
00130 _pages.append( new Page(_data) );
00131 }
00132
00133 void Device::endPage()
00134 {
00135 if ( !_currentImage.image.isNull() ) addImage();
00136 current()->endPage();
00137 clear();
00138 kdDebug(30516) << "-- end page --------------------------" << endl;
00139 }
00140
00141 void Device::updateFont(GfxState *state)
00142 {
00143 current()->updateFont(state);
00144 }
00145
00146 void Device::beginString(GfxState *state, GString *)
00147 {
00148 current()->beginString(state, state->getCurX(), state->getCurY());
00149 }
00150
00151 void Device::endString(GfxState *)
00152 {
00153 current()->endString();
00154 }
00155
00156 void Device::drawChar(GfxState *state, double x, double y,
00157 double dx, double dy, double, double,
00158 CharCode, Unicode *u, int uLen)
00159 {
00160 current()->addChar(state, x, y, dx, dy, u, uLen);
00161 }
00162
00163 void Device::drawLink(::Link* link, Catalog *cat)
00164 {
00165 double x1, y1, x2, y2, w;
00166 link->getBorder(&x1, &y1, &x2, &y2, &w);
00167
00168 int ux1, uy1, ux2, uy2;
00169 cvtUserToDev(x1, y1, &ux1, &uy1);
00170 cvtUserToDev(x2, y2, &ux2, &uy2);
00171
00172 DRect r(kMin(ux1, ux2), kMax(ux1, ux2), kMin(uy1, uy2), kMax(uy1, uy2));
00173 Link *l = new Link(r, *link->getAction(), *cat);
00174 current()->addLink(l);
00175 }
00176
00177 void Device::addImage()
00178 {
00179
00180 if ( _currentImage.image.width()==0 || _currentImage.image.height()==0 ) {
00181 kdDebug(30516) << "image has null width or height !" << endl;
00182 _currentImage = Image();
00183 return;
00184 }
00185
00186
00187
00188 ImageList::iterator it;
00189 for (it=_images.begin(); it!=_images.end(); ++it) {
00190 if ( (*it).rect==_currentImage.rect
00191 && (*it).image==_currentImage.image ) {
00192 kdDebug(30516) << "image already there !\n";
00193 _currentImage = Image();
00194 return;
00195 }
00196 }
00197
00198
00199 QString name = QString("pictures/picture%1.png").arg(_data.imageIndex());
00200 QDomElement frameset = _data.pictureFrameset(_currentImage.rect);
00201 current()->pictures.append(frameset);
00202 QDomElement picture = _data.createElement("PICTURE");
00203 picture.setAttribute("keepAspectRatio", "false");
00204 frameset.appendChild(picture);
00205
00206 QDomElement key = _data.createElement("KEY");
00207 key.setAttribute("msec", 0);
00208 key.setAttribute("second", 0);
00209 key.setAttribute("minute", 0);
00210 key.setAttribute("hour", 0);
00211 key.setAttribute("day", 1);
00212 key.setAttribute("month", 1);
00213 key.setAttribute("year", 1970);
00214 key.setAttribute("filename", name);
00215 picture.appendChild(key);
00216
00217 key = _data.createElement("KEY");
00218 key.setAttribute("msec", 0);
00219 key.setAttribute("second", 0);
00220 key.setAttribute("minute", 0);
00221 key.setAttribute("hour", 0);
00222 key.setAttribute("day", 1);
00223 key.setAttribute("month", 1);
00224 key.setAttribute("year", 1970);
00225 key.setAttribute("filename", name);
00226 key.setAttribute("name", name);
00227 _data.pictures().appendChild(key);
00228
00229 KoStoreDevice *sd = _data.chain()->storageFile(name, KoStore::Write);
00230 QImageIO io(sd, "PNG");
00231 io.setImage(_currentImage.image);
00232 bool ok = io.write();
00233 Q_ASSERT(ok);
00234 sd->close();
00235
00236 _images.append(_currentImage);
00237 _currentImage = Image();
00238 }
00239
00240 void Device::computeGeometry(GfxState *state, Image &image)
00241 {
00242 double xt, yt, wt, ht;
00243 state->transform(0, 0, &xt, &yt);
00244 state->transformDelta(1, 1, &wt, &ht);
00245 image.rect.setLeft(xt + (wt>0 ? 0 : wt));
00246 image.rect.setRight(image.rect.left() + fabs(wt));
00247 image.rect.setTop(yt + (ht>0 ? 0 : ht));
00248 image.rect.setBottom(image.rect.top() + fabs(ht));
00249
00250
00251 }
00252
00253 uint Device::initImage(GfxState *state, int width, int height,
00254 bool withMask)
00255 {
00256
00257 Image image;
00258 image.mask = withMask;
00259 computeGeometry(state, image);
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271 if ( !_currentImage.image.isNull() &&
00272 (_currentImage.image.width()!=width
00273 || !equal(image.rect.left(), _currentImage.rect.left())
00274 || !equal(image.rect.right(), _currentImage.rect.right())
00275 || !equal(image.rect.top(), _currentImage.rect.bottom())
00276 || image.mask!=_currentImage.mask) )
00277 addImage();
00278
00279 uint offset =
00280 (_currentImage.image.isNull() ? 0 : _currentImage.image.height());
00281 image.image = QImage(width, offset + height, 32);
00282 image.image.setAlphaBuffer(withMask);
00283 if ( !_currentImage.image.isNull() ) {
00284
00285 for (int j=0; j<_currentImage.image.height(); j++) {
00286 QRgb *pix = (QRgb *)_currentImage.image.scanLine(j);
00287 QRgb *newPix = (QRgb *)image.image.scanLine(j);
00288 for (int i=0; i<width; i++) newPix[i] = pix[i];
00289 }
00290 _currentImage.image = image.image;
00291 _currentImage.rect.setBottom( image.rect.bottom() );
00292 } else _currentImage = image;
00293 return offset;
00294 }
00295
00296 void Device::drawImage(GfxState *state, Object *, Stream *str,
00297 int width, int height, GfxImageColorMap *colorMap,
00298 int *maskColors, GBool inlineImg)
00299 {
00300 kdDebug(30516) << "image kind=" << str->getKind()
00301 << " inline=" << inlineImg
00302 << " maskColors=" << (maskColors!=0) << endl;
00303 if ( !_data.options().importImages ) return;
00304
00305 uint offset = initImage(state, width, height, maskColors!=0);
00306
00307
00308 int nbComps = colorMap->getNumPixelComps();
00309 int nbBits = colorMap->getBits();
00310 ImageStream *istr = new ImageStream(str, width, nbComps, nbBits);
00311 istr->reset();
00312 for (int j=0; j<height; j++) {
00313 Guchar *p = istr->getLine();
00314 QRgb *pix = (QRgb *)_currentImage.image.scanLine(offset + j);
00315 for (int i=0; i<width; i++) {
00316 GfxRGB rgb;
00317 colorMap->getRGB(p, &rgb);
00318 int alpha = 255;
00319 if (maskColors) {
00320 for (int k=0; k<nbComps; k++)
00321 if ( p[k]<maskColors[2*k] || p[k]>maskColors[2*k+1] ) {
00322 alpha = 0;
00323 break;
00324 }
00325 }
00326 pix[i] = qRgba(qRound(rgb.r*255), qRound(rgb.g*255),
00327 qRound(rgb.b*255), alpha);
00328 p += nbComps;
00329 }
00330 }
00331 delete istr;
00332 }
00333
00334 void Device::drawImageMask(GfxState *state, Object *, Stream *str,
00335 int width, int height, GBool invert,
00336 GBool inlineImg)
00337 {
00338 kdDebug(30516) << "image mask ! kind=" << str->getKind()
00339 << "inline=" << inlineImg << endl;
00340 if ( !_data.options().importImages ) return;
00341
00342 uint offset = initImage(state, width, height, true);
00343
00344
00345 GfxRGB rgb;
00346 state->getFillRGB(&rgb);
00347 int red = qRound(rgb.r * 255);
00348 int green = qRound(rgb.g * 255);
00349 int blue = qRound(rgb.b * 255);
00350
00351 ImageStream *istr = new ImageStream(str, width, 1, 1);
00352 str->reset();
00353 for (int j=0; j<height; j++) {
00354 Guchar *p = istr->getLine();
00355 QRgb *pix = (QRgb *)_currentImage.image.scanLine(offset + j);
00356 for (int i=0; i<width; i++)
00357 pix[i] = qRgba(red, green, blue, 255 * p[i]);
00358 }
00359 delete istr;
00360
00361 if (invert) _currentImage.image.invertPixels();
00362 }
00363
00364 void Device::updateAll(GfxState *state)
00365 {
00366 updateFillColor(state);
00367 updateStrokeColor(state);
00368 updateFont(state);
00369 }
00370
00371 void Device::updateFillColor(GfxState *state)
00372 {
00373 GfxRGB rgb;
00374 state->getFillRGB(&rgb);
00375 _fillColor = toColor(rgb);
00376 }
00377
00378 void Device::updateStrokeColor(GfxState *state)
00379 {
00380 GfxRGB rgb;
00381 state->getStrokeRGB(&rgb);
00382 _strokeColor = toColor(rgb);
00383 }
00384
00385 void Device::stroke(GfxState *)
00386 {
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 }
00406
00407 void Device::fill(GfxState *)
00408 {
00409
00410
00411 }
00412
00413 void Device::eoFill(GfxState *)
00414 {
00415
00416
00417
00418 }
00419
00420 void Device::doFill(const DPathVector &path)
00421 {
00422 for (uint i=0; i<path.size(); i++) {
00423 if ( path[i].isSegment() ) continue;
00424 if ( path[i].isRectangle() ) {
00425 kdDebug(30516) << "fill rectangle" << endl;
00426 if ( !_currentImage.image.isNull() ) addImage();
00427 _currentImage.rect = path[i].boundingRect();
00428 _currentImage.image =
00429 QImage(qRound(_currentImage.rect.width()),
00430 qRound(_currentImage.rect.height()), 32);
00431 _currentImage.image.fill(_fillColor.pixel());
00432 addImage();
00433 }
00434 }
00435 }
00436
00437 DPathVector Device::convertPath(GfxState *state)
00438 {
00439 GfxPath *path = state->getPath();
00440 uint nbPaths = path->getNumSubpaths();
00441 DPathVector vector;
00442 for (uint i=0; i<nbPaths; i++) {
00443 GfxSubpath *spath = path->getSubpath(i);
00444 uint nbPoints = spath->getNumPoints();
00445 DPath dpath;
00446 for (uint k=0; k<nbPoints; k++) {
00447 if ( k>=1 && spath->getCurve(k) ) {
00448 kdDebug(30516) << " bezier curve : ignore !" << endl;
00449 dpath = DPath();
00450 break;
00451 } else {
00452 DPoint dpoint;
00453 state->transform(spath->getX(k), spath->getY(k),
00454 &dpoint.x, &dpoint.y);
00455 dpath.push_back(dpoint);
00456 }
00457 }
00458 if ( dpath.size()!=0 ) vector.push_back(dpath);
00459 }
00460 return vector;
00461 }
00462
00463 }