Added support for Illustrator previews (%AI7_Thumbnail) in EPS files, decoded to *.pnm

This commit is contained in:
vog
2011-08-17 21:10:53 +00:00
parent 731c60fb65
commit 058f1ea221
30 changed files with 201 additions and 12 deletions
+45
View File
@@ -417,6 +417,8 @@ namespace {
size_t posExiv2Version = posEndEps;
size_t posExiv2Website = posEndEps;
size_t posEndComments = posEndEps;
size_t posAi7Thumbnail = posEndEps;
size_t posAi7ThumbnailEndData = posEndEps;
size_t posBeginPhotoshop = posEndEps;
size_t posEndPhotoshop = posEndEps;
size_t posPage = posEndEps;
@@ -543,6 +545,10 @@ namespace {
posExiv2Website = startPos;
} else if (posEndComments == posEndEps && startsWith(line, "%%Creator: Adobe Illustrator") && firstLine == "%!PS-Adobe-3.0 EPSF-3.0") {
illustrator8 = true;
} else if (posEndComments == posEndEps && startsWith(line, "%AI7_Thumbnail:")) {
posAi7Thumbnail = startPos;
} else if (posEndComments == posEndEps && posAi7Thumbnail != posEndEps && posAi7ThumbnailEndData == posEndEps && line == "%%EndData") {
posAi7ThumbnailEndData = startPos;
} else if (posEndComments == posEndEps && line == "%%EndComments") {
posEndComments = startPos;
} else if (line == "%%EndPreview") {
@@ -711,6 +717,45 @@ namespace {
// native previews
nativePreviews.clear();
if (posAi7ThumbnailEndData != posEndEps) {
NativePreview nativePreview;
std::string dummy;
std::string lineAi7Thumbnail;
const size_t posBeginData = readLine(lineAi7Thumbnail, data, posAi7Thumbnail, posEndEps);
std::istringstream lineStreamAi7Thumbnail(lineAi7Thumbnail);
lineStreamAi7Thumbnail >> dummy;
lineStreamAi7Thumbnail >> nativePreview.width_;
lineStreamAi7Thumbnail >> nativePreview.height_;
std::string depth;
lineStreamAi7Thumbnail >> depth;
std::string lineBeginData;
const size_t posAfterBeginData = readLine(lineBeginData, data, posBeginData, posEndEps);
std::istringstream lineStreamBeginData(lineBeginData);
std::string beginData;
lineStreamBeginData >> beginData;
lineStreamBeginData >> dummy;
std::string type;
lineStreamBeginData >> type;
nativePreview.position_ = static_cast<long>(posAfterBeginData);
nativePreview.size_ = posAi7ThumbnailEndData - posAfterBeginData;
nativePreview.filter_ = "hex-ai7thumbnail-pnm";
nativePreview.mimeType_ = "image/x-portable-anymap";
if (depth != "8") {
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Unable to handle Illustrator thumbnail depth: " << depth << "\n";
#endif
} else if (beginData != "%%BeginData:") {
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Unable to handle Illustrator thumbnail data section: " << lineBeginData << "\n";
#endif
} else if (type != "Hex") {
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Unable to handle Illustrator thumbnail data type: " << type << "\n";
#endif
} else {
nativePreviews.push_back(nativePreview);
}
}
if (posEndPhotoshop != posEndEps) {
NativePreview nativePreview;
nativePreview.position_ = static_cast<long>(posBeginPhotoshop);
+1
View File
@@ -25,6 +25,7 @@
<br>[1] <a href="http://partners.adobe.com/public/developer/en/ps/5001.DSC_Spec.pdf">Adobe PostScript Language Document Structuring Conventions Specification, Version 3.0</a>, September 1992
<br>[2] <a href="http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf">Adobe Encapsulated PostScript File Format Specification, Version 3.0</a>, May 1992
<br>[3] <a href="http://www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf">Adobe XMP Specification Part 3: Storage in Files</a>, July 2010
<br>[4] <a href="http://groups.google.com/group/adobe.illustrator.windows/msg/0a9d7b1244b59062">Re: Thumbnail data format in ai file</a>, Dec 2003
@version $Rev: $
@author Michael Ulbrich (mul)
<a href="mailto:mul@rentapacs.de">mul@rentapacs.de</a>
+78
View File
@@ -78,6 +78,16 @@ namespace {
*/
DataBuf decodeBase64(const std::string &src);
/*!
@brief Decode an Illustrator thumbnail that follows after %AI7_Thumbnail.
*/
DataBuf decodeAi7Thumbnail(const DataBuf &src);
/*!
@brief Create a PNM image from raw RGB data.
*/
DataBuf makePnm(uint32_t width, uint32_t height, const DataBuf &rgb);
/*!
Base class for image loaders. Provides virtual methods for reading properties
and DataBuf.
@@ -434,6 +444,8 @@ namespace {
prop.extension_ = ".tif";
} else if (nativePreview_.mimeType_ == "image/x-wmf") {
prop.extension_ = ".wmf";
} else if (nativePreview_.mimeType_ == "image/x-portable-anymap") {
prop.extension_ = ".pnm";
} else {
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Unknown native preview format: " << nativePreview_.mimeType_ << "\n";
@@ -464,6 +476,10 @@ namespace {
}
if (nativePreview_.filter_ == "") {
return DataBuf(data + nativePreview_.position_, static_cast<long>(nativePreview_.size_));
} else if (nativePreview_.filter_ == "hex-ai7thumbnail-pnm") {
const DataBuf ai7thumbnail = decodeHex(data + nativePreview_.position_, static_cast<long>(nativePreview_.size_));
const DataBuf rgb = decodeAi7Thumbnail(ai7thumbnail);
return makePnm(width_, height_, rgb);
} else if (nativePreview_.filter_ == "hex-irb") {
const DataBuf psData = decodeHex(data + nativePreview_.position_, static_cast<long>(nativePreview_.size_));
const byte *record;
@@ -957,6 +973,68 @@ namespace {
return dest;
}
DataBuf decodeAi7Thumbnail(const DataBuf &src)
{
const byte *colorTable = src.pData_;
const long colorTableSize = 256 * 3;
if (src.size_ < colorTableSize) {
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Invalid size of AI7 thumbnail: " << src.size_ << "\n";
#endif
return DataBuf();
}
const byte *imageData = src.pData_ + colorTableSize;
const long imageDataSize = src.size_ - colorTableSize;
const bool rle = (imageDataSize >= 3 && imageData[0] == 'R' && imageData[1] == 'L' && imageData[2] == 'E');
std::string dest;
for (long i = rle ? 3 : 0; i < imageDataSize;) {
byte num = 1;
byte value = imageData[i++];
if (rle && value == 0xFD) {
if (i >= imageDataSize) {
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Unexpected end of image data at AI7 thumbnail.\n";
#endif
return DataBuf();
}
value = imageData[i++];
if (value != 0xFD) {
if (i >= imageDataSize) {
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Unexpected end of image data at AI7 thumbnail.\n";
#endif
return DataBuf();
}
num = value;
value = imageData[i++];
}
}
for (; num != 0; num--) {
dest.append(reinterpret_cast<const char*>(colorTable + (3*value)), 3);
}
}
return DataBuf(reinterpret_cast<const byte*>(dest.data()), static_cast<long>(dest.size()));
}
DataBuf makePnm(uint32_t width, uint32_t height, const DataBuf &rgb)
{
const long expectedSize = static_cast<long>(width * height * 3);
if (rgb.size_ != expectedSize) {
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Invalid size of preview data. Expected " << expectedSize << " bytes, got " << rgb.size_ << " bytes.\n";
#endif
return DataBuf();
}
const std::string header = "P6\n" + toString(width) + " " + toString(height) + "\n255\n";
const byte *headerBytes = reinterpret_cast<const byte*>(header.data());
DataBuf dest(header.size() + rgb.size_);
std::copy(headerBytes, headerBytes + header.size(), dest.pData_);
std::copy(rgb.pData_, rgb.pData_ + rgb.size_, dest.pData_ + header.size());
return dest;
}
} // namespace
// *****************************************************************************
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

+25 -12
View File
@@ -14,7 +14,8 @@ Exit code: 1
-----> eps-flat_oodraw_ai-10-lev2.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-10-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-10-lev2.eps
@@ -23,7 +24,8 @@ Exit code: 0
-----> eps-flat_oodraw_ai-8-lev2.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-8-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-8-lev2.eps
@@ -32,6 +34,7 @@ Exit code: 0
-----> eps-flat_oodraw_ai-8-lev3.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-8-lev3.eps
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-8-lev3.eps
@@ -40,7 +43,8 @@ Exit code: 0
-----> eps-flat_oodraw_ai-9-lev2.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-9-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-9-lev2.eps
@@ -49,7 +53,8 @@ Exit code: 0
-----> eps-flat_oodraw_ai-cs-lev2.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-cs-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-cs-lev2.eps
@@ -58,7 +63,8 @@ Exit code: 0
-----> eps-flat_oodraw_ai-cs2-lev2.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-cs2-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-cs2-lev2.eps
@@ -67,7 +73,8 @@ Exit code: 0
-----> eps-flat_oodraw_ai-cs3-lev2.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-cs3-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-cs3-lev2.eps
@@ -76,7 +83,8 @@ Exit code: 0
-----> eps-flat_oodraw_ai-cs4-lev2.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-cs4-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-cs4-lev2.eps
@@ -85,7 +93,8 @@ Exit code: 0
-----> eps-flat_oodraw_ai-cs5-lev2.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-cs5-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-cs5-lev2.eps
@@ -103,8 +112,9 @@ Exit code: 0
-----> eps-flat_oodraw_ai-cs5-lev3-pre.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-cs5-lev3-pre.eps
Preview 1: image/tiff, 213x170 pixels, 37902 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/tiff, 213x170 pixels, 37902 bytes
Preview 3: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-cs5-lev3-pre.eps
@@ -113,7 +123,8 @@ Exit code: 0
-----> eps-flat_oodraw_ai-cs5-lev3.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-cs5-lev3.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-cs5-lev3.eps
@@ -122,6 +133,7 @@ Exit code: 0
-----> eps-flat_oodraw_ai-cs5-lev3_exiftool-8.56.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-cs5-lev3_exiftool-8.56.eps
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-cs5-lev3_exiftool-8.56.eps
@@ -130,7 +142,8 @@ Exit code: 0
-----> eps-flat_oodraw_ai-cs5-lev3_ns-xapGImg.eps <-----
Command: exiv2 -pp eps-flat_oodraw_ai-cs5-lev3_ns-xapGImg.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Preview 1: image/x-portable-anymap, 128x104 pixels, 39951 bytes
Preview 2: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -ep eps-flat_oodraw_ai-cs5-lev3_ns-xapGImg.eps