QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device, int *accuracyPtr) { // First, glob patterns are evaluated. If there is a match with max weight, // this one is selected and we are done. Otherwise, the file contents are // evaluated and the match with the highest value (either a magic priority or // a glob pattern weight) is selected. Matching starts from max level (most // specific) in both cases, even when there is already a suffix matching candidate. *accuracyPtr = 0; // Pass 1) Try to match on the file name QStringList candidatesByName = mimeTypeForFileName(fileName); if (candidatesByName.count() == 1) { *accuracyPtr = 100; const QMimeType mime = mimeTypeForName(candidatesByName.at(0)); if (mime.isValid()) return mime; candidatesByName.clear(); } // Extension is unknown, or matches multiple mimetypes. // Pass 2) Match on content, if we can read the data if (device->isOpen()) { // Read 16K in one go (QIODEVICE_BUFFERSIZE in qiodevice_p.h). // This is much faster than seeking back and forth into QIODevice. const QByteArray data = device->peek(16384); int magicAccuracy = 0; QMimeType candidateByData(findByData(data, &magicAccuracy)); // Disambiguate conflicting extensions (if magic matching found something) if (candidateByData.isValid() && magicAccuracy > 0) { // "for glob_match in glob_matches:" // "if glob_match is subclass or equal to sniffed_type, use glob_match" const QString sniffedMime = candidateByData.name(); foreach (const QString &m, candidatesByName) { if (inherits(m, sniffedMime)) { // We have magic + pattern pointing to this, so it's a pretty good match *accuracyPtr = 100; return mimeTypeForName(m); } } *accuracyPtr = magicAccuracy; return candidateByData; } } if (candidatesByName.count() > 1) { *accuracyPtr = 20; candidatesByName.sort(); // to make it deterministic const QMimeType mime = mimeTypeForName(candidatesByName.at(0)); if (mime.isValid()) return mime; } return mimeTypeForName(defaultMimeType()); }
QMimeType QMimeDatabasePrivate::findByData(const QByteArray &data, int *accuracyPtr) { if (data.isEmpty()) { *accuracyPtr = 100; return mimeTypeForName(QLatin1String("application/x-zerosize")); } *accuracyPtr = 0; QMimeType candidate = provider()->findByMagic(data, accuracyPtr); if (candidate.isValid()) return candidate; if (isTextFile(data)) { *accuracyPtr = 5; return mimeTypeForName(QLatin1String("text/plain")); } return mimeTypeForName(defaultMimeType()); }
void ScanDialog::slotSaveImage(QByteArray& ksane_data, int width, int height, int bytes_per_line, int ksaneformat) { QStringList writableMimetypes = KImageIO::mimeTypes(KImageIO::Writing); // Put first class citizens at first place writableMimetypes.removeAll("image/jpeg"); writableMimetypes.removeAll("image/tiff"); writableMimetypes.removeAll("image/png"); writableMimetypes.insert(0, "image/png"); writableMimetypes.insert(1, "image/jpeg"); writableMimetypes.insert(2, "image/tiff"); kDebug() << "slotSaveImage: Offered mimetypes: " << writableMimetypes; QString defaultMimeType("image/png"); QString defaultFileName("image.png"); QString format("PNG"); QString place = QDir::homePath(); if (iface()) place = iface()->currentAlbum().uploadPath().path(); QPointer<KFileDialog> imageFileSaveDialog = new KFileDialog(place, QString(), 0); imageFileSaveDialog->setModal(false); imageFileSaveDialog->setOperationMode(KFileDialog::Saving); imageFileSaveDialog->setMode(KFile::File); imageFileSaveDialog->setSelection(defaultFileName); imageFileSaveDialog->setCaption(i18n("New Image File Name")); imageFileSaveDialog->setMimeFilter(writableMimetypes, defaultMimeType); // Start dialog and check if canceled. if ( imageFileSaveDialog->exec() != KFileDialog::Accepted ) { delete imageFileSaveDialog; return; } KUrl newURL = imageFileSaveDialog->selectedUrl(); QFileInfo fi(newURL.toLocalFile()); // Check if target image format have been selected from Combo List of dialog. const QStringList mimes = KImageIO::typeForMime(imageFileSaveDialog->currentMimeFilter()); if (!mimes.isEmpty()) { format = mimes.first().toUpper(); } else { // Else, check if target image format have been add to target image file name using extension. format = fi.suffix().toUpper(); // Check if format from file name extension is include on file mime type list. QStringList imgExtList = KImageIO::types(KImageIO::Writing); imgExtList << "TIF"; imgExtList << "TIFF"; imgExtList << "JPG"; imgExtList << "JPE"; if ( !imgExtList.contains( format ) ) { KMessageBox::error(0, i18n("The target image file format \"%1\" is unsupported.", format)); kWarning() << "target image file format " << format << " is unsupported!"; delete imageFileSaveDialog; return; } } if (!newURL.isValid()) { KMessageBox::error(0, i18n("Failed to save file\n\"%1\" to\n\"%2\".", newURL.fileName(), newURL.path().section('/', -2, -2))); kWarning() << "target URL is not valid !"; delete imageFileSaveDialog; return; } // Check for overwrite ---------------------------------------------------------- if ( fi.exists() ) { int result = KMessageBox::warningYesNo(0, i18n("A file named \"%1\" already " "exists. Are you sure you want " "to overwrite it?", newURL.fileName()), i18n("Overwrite File?"), KStandardGuiItem::overwrite(), KStandardGuiItem::cancel()); if (result != KMessageBox::Yes) { delete imageFileSaveDialog; return; } } delete imageFileSaveDialog; setCursor(Qt::WaitCursor); setEnabled(false); saveSettings(); // Perform saving --------------------------------------------------------------- d->saveThread->setImageData(ksane_data, width, height, bytes_per_line, ksaneformat); d->saveThread->setPreviewImage(d->saneWidget->toQImage(ksane_data, width, height, bytes_per_line, (KSaneWidget::ImageFormat)ksaneformat)); d->saveThread->setTargetFile(newURL, format); d->saveThread->setScannerModel(d->saneWidget->make(), d->saneWidget->model()); d->saveThread->start(); }