void CacheDrivenTask::process( PageInfo const& page_info, AbstractFilterDataCollector* collector, ImageTransformation const& xform, QPolygonF const& content_rect_phys) { if (ThumbnailCollector* thumb_col = dynamic_cast<ThumbnailCollector*>(collector)) { QString const out_file_path(m_outFileNameGen.filePathFor(page_info.id())); Params const params(m_ptrSettings->getParams(page_info.id())); ImageTransformation new_xform(xform); new_xform.postScaleToDpi(params.outputDpi()); bool need_reprocess = false; do { // Just to be able to break from it. std::auto_ptr<OutputParams> stored_output_params( m_ptrSettings->getOutputParams(page_info.id()) ); if (!stored_output_params.get()) { need_reprocess = true; break; } OutputGenerator const generator( params.outputDpi(), params.colorParams(), params.despeckleLevel(), new_xform, content_rect_phys ); OutputImageParams const new_output_image_params( generator.outputImageSize(), generator.outputContentRect(), new_xform, params.outputDpi(), params.colorParams(), params.dewarpingMode(), params.distortionModel(), params.depthPerception(), params.despeckleLevel() ); if (!stored_output_params->outputImageParams().matches(new_output_image_params)) { need_reprocess = true; break; } ZoneSet const new_picture_zones(m_ptrSettings->pictureZonesForPage(page_info.id())); if (!PictureZoneComparator::equal(stored_output_params->pictureZones(), new_picture_zones)) { need_reprocess = true; break; } ZoneSet const new_fill_zones(m_ptrSettings->fillZonesForPage(page_info.id())); if (!FillZoneComparator::equal(stored_output_params->fillZones(), new_fill_zones)) { need_reprocess = true; break; } QFileInfo const out_file_info(out_file_path); if (!out_file_info.exists()) { need_reprocess = true; break; } if (!stored_output_params->outputFileParams().matches(OutputFileParams(out_file_info))) { need_reprocess = true; break; } } while (false); if (need_reprocess) { thumb_col->processThumbnail( std::auto_ptr<QGraphicsItem>( new IncompleteThumbnail( thumb_col->thumbnailCache(), thumb_col->maxLogicalThumbSize(), page_info.imageId(), new_xform ) ) ); } else { ImageTransformation const out_xform( new_xform.resultingRect(), params.outputDpi() ); thumb_col->processThumbnail( std::auto_ptr<QGraphicsItem>( new Thumbnail( thumb_col->thumbnailCache(), thumb_col->maxLogicalThumbSize(), ImageId(out_file_path), out_xform ) ) ); } } }
FilterResultPtr Task::process( TaskStatus const& status, FilterData const& data, QPolygonF const& content_rect_phys, QPolygonF const& page_rect_phys) { status.throwIfCancelled(); Params const params(m_ptrSettings->getParams(m_pageId)); RenderParams const render_params(params.colorParams()); QString const out_file_path(m_outFileNameGen.filePathFor(m_pageId)); QFileInfo const out_file_info(out_file_path); QString const automask_dir(Utils::automaskDir(m_outFileNameGen.outDir())); QString const automask_file_path( QDir(automask_dir).absoluteFilePath(out_file_info.fileName()) ); QFileInfo automask_file_info(automask_file_path); QString const speckles_dir(Utils::specklesDir(m_outFileNameGen.outDir())); QString const speckles_file_path( QDir(speckles_dir).absoluteFilePath(out_file_info.fileName()) ); QFileInfo speckles_file_info(speckles_file_path); bool const need_picture_editor = render_params.mixedOutput() && !m_batchProcessing; bool const need_speckles_image = params.despeckleLevel() != DESPECKLE_OFF && params.colorParams().colorMode() != ColorParams::COLOR_GRAYSCALE && !m_batchProcessing; OutputGenerator const generator( params.outputDpi(), params.colorParams(), params.despeckleLevel(), data.xform(), content_rect_phys, page_rect_phys ); OutputImageParams const new_output_image_params( generator.outputImageSize(), generator.outputContentRect(), data.xform(), params.outputDpi(), params.colorParams(), params.dewarpingMode(), params.distortionModel(), params.depthPerception(), params.despeckleLevel() ); ZoneSet const new_picture_zones(m_ptrSettings->pictureZonesForPage(m_pageId)); ZoneSet const new_fill_zones(m_ptrSettings->fillZonesForPage(m_pageId)); bool need_reprocess = false; do { // Just to be able to break from it. std::auto_ptr<OutputParams> stored_output_params( m_ptrSettings->getOutputParams(m_pageId) ); if (!stored_output_params.get()) { need_reprocess = true; break; } if (!stored_output_params->outputImageParams().matches(new_output_image_params)) { need_reprocess = true; break; } if (!PictureZoneComparator::equal(stored_output_params->pictureZones(), new_picture_zones)) { need_reprocess = true; break; } if (!FillZoneComparator::equal(stored_output_params->fillZones(), new_fill_zones)) { need_reprocess = true; break; } if (!out_file_info.exists()) { need_reprocess = true; break; } if (!stored_output_params->outputFileParams().matches(OutputFileParams(out_file_info))) { need_reprocess = true; break; } if (need_picture_editor) { if (!automask_file_info.exists()) { need_reprocess = true; break; } if (!stored_output_params->automaskFileParams().matches(OutputFileParams(automask_file_info))) { need_reprocess = true; break; } } if (need_speckles_image) { if (!speckles_file_info.exists()) { need_reprocess = true; break; } if (!stored_output_params->specklesFileParams().matches(OutputFileParams(speckles_file_info))) { need_reprocess = true; break; } } } while (false); QImage out_img; BinaryImage automask_img; BinaryImage speckles_img; if (!need_reprocess) { QFile out_file(out_file_path); if (out_file.open(QIODevice::ReadOnly)) { out_img = ImageLoader::load(out_file, 0); } need_reprocess = out_img.isNull(); if (need_picture_editor && !need_reprocess) { QFile automask_file(automask_file_path); if (automask_file.open(QIODevice::ReadOnly)) { automask_img = BinaryImage(ImageLoader::load(automask_file, 0)); } need_reprocess = automask_img.isNull() || automask_img.size() != out_img.size(); } if (need_speckles_image && !need_reprocess) { QFile speckles_file(speckles_file_path); if (speckles_file.open(QIODevice::ReadOnly)) { speckles_img = BinaryImage(ImageLoader::load(speckles_file, 0)); } need_reprocess = speckles_img.isNull(); } } if (need_reprocess) { // Even in batch processing mode we should still write automask, because it // will be needed when we view the results back in interactive mode. // The same applies even more to speckles file, as we need it not only // for visualization purposes, but also for re-doing despeckling at // different levels without going through the whole output generation process. bool const write_automask = render_params.mixedOutput(); bool const write_speckles_file = params.despeckleLevel() != DESPECKLE_OFF && params.colorParams().colorMode() != ColorParams::COLOR_GRAYSCALE; automask_img = BinaryImage(); speckles_img = BinaryImage(); out_img = generator.process( status, data, new_picture_zones, new_fill_zones, params.dewarpingMode() != DewarpingMode::OFF ? params.distortionModel() : DistortionModel(), params.depthPerception(), write_automask ? &automask_img : 0, write_speckles_file ? &speckles_img : 0, m_ptrDbg.get() ); if (write_speckles_file && speckles_img.isNull()) { // Even if despeckling didn't actually take place, we still need // to write an empty speckles file. Making it a special case // is simply not worth it. BinaryImage(out_img.size(), WHITE).swap(speckles_img); } bool invalidate_params = false; if (!TiffWriter::writeImage(out_file_path, out_img)) { invalidate_params = true; } else { deleteMutuallyExclusiveOutputFiles(); } if (write_automask) { if (!QDir().mkpath(automask_dir)) { invalidate_params = true; } else if (!TiffWriter::writeImage(automask_file_path, automask_img.toQImage())) { invalidate_params = true; } } if (write_speckles_file) { if (!QDir().mkpath(speckles_dir)) { invalidate_params = true; } else if (!TiffWriter::writeImage(speckles_file_path, speckles_img.toQImage())) { invalidate_params = true; } } if (invalidate_params) { m_ptrSettings->removeOutputParams(m_pageId); } else { // Note that we can't reuse *_file_info objects // as we've just overwritten those files. OutputParams const out_params( new_output_image_params, OutputFileParams(QFileInfo(out_file_path)), write_automask ? OutputFileParams(QFileInfo(automask_file_path)) : OutputFileParams(), write_speckles_file ? OutputFileParams(QFileInfo(speckles_file_path)) : OutputFileParams(), new_picture_zones, new_fill_zones ); m_ptrSettings->setOutputParams(m_pageId, out_params); } m_ptrThumbnailCache->recreateThumbnail(ImageId(out_file_path), out_img); } DespeckleState const despeckle_state( out_img, speckles_img, params.despeckleLevel(), params.outputDpi() ); DespeckleVisualization despeckle_visualization; if (m_lastTab == TAB_DESPECKLING) { // Because constructing DespeckleVisualization takes a noticeable // amount of time, we only do it if we are sure we'll need it. // Otherwise it will get constructed on demand. despeckle_visualization = despeckle_state.visualize(); } return FilterResultPtr( new UiUpdater( m_ptrFilter, m_ptrSettings, m_ptrDbg, params, generator.toOutput(), generator.outputContentRect(), QRectF(QPointF(0.0, 0.0), generator.outputImageSize()), m_pageId, data.origImage(), out_img, automask_img, params.distortionModel(), despeckle_state, despeckle_visualization, m_batchProcessing, m_debug ) ); }