From bc87894e844c3549ccec13b52a73e9b9b5354d9f Mon Sep 17 00:00:00 2001 From: Gerasim Troeglazov <3dEyes@gmail.com> Date: Sun, 1 Dec 2013 11:42:04 +0000 Subject: [PATCH] Add simple translator for PSD (Adobe Photoshop) format --- src/add-ons/translators/psd/ConfigView.cpp | 78 ++++++ src/add-ons/translators/psd/ConfigView.h | 30 +++ src/add-ons/translators/psd/Jamfile | 26 ++ src/add-ons/translators/psd/PSDLoader.cpp | 228 ++++++++++++++++++ src/add-ons/translators/psd/PSDLoader.h | 61 +++++ src/add-ons/translators/psd/PSDTranslator.cpp | 147 +++++++++++ src/add-ons/translators/psd/PSDTranslator.h | 56 +++++ .../translators/psd/PSDTranslator.rdef | 15 ++ .../translators/psd/PSDTranslatorApp.cpp | 25 ++ 9 files changed, 666 insertions(+) create mode 100644 src/add-ons/translators/psd/ConfigView.cpp create mode 100644 src/add-ons/translators/psd/ConfigView.h create mode 100644 src/add-ons/translators/psd/Jamfile create mode 100644 src/add-ons/translators/psd/PSDLoader.cpp create mode 100644 src/add-ons/translators/psd/PSDLoader.h create mode 100644 src/add-ons/translators/psd/PSDTranslator.cpp create mode 100644 src/add-ons/translators/psd/PSDTranslator.h create mode 100644 src/add-ons/translators/psd/PSDTranslator.rdef create mode 100644 src/add-ons/translators/psd/PSDTranslatorApp.cpp diff --git a/src/add-ons/translators/psd/ConfigView.cpp b/src/add-ons/translators/psd/ConfigView.cpp new file mode 100644 index 0000000000..0279493bed --- /dev/null +++ b/src/add-ons/translators/psd/ConfigView.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#include "ConfigView.h" +#include "PSDTranslator.h" + +#include +#include +#include + +#include + + +ConfigView::ConfigView(TranslatorSettings *settings) + : BGroupView("PSDTranslator Settings", B_VERTICAL, 0) +{ + fSettings = settings; + + BAlignment leftAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_UNSET); + + BStringView *stringView = new BStringView("title", "Photoshop image translator"); + stringView->SetFont(be_bold_font); + stringView->SetExplicitAlignment(leftAlignment); + AddChild(stringView); + + float spacing = be_control_look->DefaultItemSpacing(); + AddChild(BSpaceLayoutItem::CreateVerticalStrut(spacing)); + + char version[256]; + sprintf(version, "Version %d.%d.%d, %s", + int(B_TRANSLATION_MAJOR_VERSION(PSD_TRANSLATOR_VERSION)), + int(B_TRANSLATION_MINOR_VERSION(PSD_TRANSLATOR_VERSION)), + int(B_TRANSLATION_REVISION_VERSION(PSD_TRANSLATOR_VERSION)), + __DATE__); + stringView = new BStringView("version", version); + stringView->SetExplicitAlignment(leftAlignment); + AddChild(stringView); + + stringView = new BStringView("copyright", + B_UTF8_COPYRIGHT "2005-2013 Haiku Inc."); + stringView->SetExplicitAlignment(leftAlignment); + AddChild(stringView); + + stringView = new BStringView("my_copyright", + B_UTF8_COPYRIGHT "2012-2013 Gerasim Troeglazov <3dEyes@gmail.com>"); + stringView->SetExplicitAlignment(leftAlignment); + AddChild(stringView); + + AddChild(BSpaceLayoutItem::CreateGlue()); + GroupLayout()->SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, + B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING); + + SetExplicitPreferredSize(GroupLayout()->MinSize()); +} + + +ConfigView::~ConfigView() +{ + fSettings->Release(); +} + + +void +ConfigView::AllAttached() +{ +} + + +void +ConfigView::MessageReceived(BMessage* message) +{ + switch (message->what) { + default: + BView::MessageReceived(message); + } +} diff --git a/src/add-ons/translators/psd/ConfigView.h b/src/add-ons/translators/psd/ConfigView.h new file mode 100644 index 0000000000..cbf43d4112 --- /dev/null +++ b/src/add-ons/translators/psd/ConfigView.h @@ -0,0 +1,30 @@ +/* + * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#ifndef CONFIG_VIEW_H +#define CONFIG_VIEW_H + +#include "TranslatorSettings.h" + +#include +#include +#include +#include +#include + +class ConfigView : public BGroupView { + public: + ConfigView(TranslatorSettings *settings); + virtual ~ConfigView(); + + virtual void AllAttached(); + virtual void MessageReceived(BMessage* message); + + private: + BTextView* fCopyrightView; + TranslatorSettings *fSettings; +}; + +#endif // CONFIG_VIEW_H diff --git a/src/add-ons/translators/psd/Jamfile b/src/add-ons/translators/psd/Jamfile new file mode 100644 index 0000000000..b0a56a53c8 --- /dev/null +++ b/src/add-ons/translators/psd/Jamfile @@ -0,0 +1,26 @@ +SubDir HAIKU_TOP src add-ons translators psd ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) shared ] ; + +AddResources PSDTranslator : PSDTranslator.rdef ; + +Translator PSDTranslator : + PSDTranslatorApp.cpp + PSDTranslator.cpp + PSDLoader.cpp + ConfigView.cpp + : be translation libtranslatorsutils.a $(TARGET_LIBSUPC++) + localestub + : true +; + +DoCatalogs PSDTranslator : + x-vnd.Haiku-PSDTranslator + : + PSDTranslatorApp.cpp + PSDTranslator.cpp + PSDLoader.cpp + ConfigView.cpp +; diff --git a/src/add-ons/translators/psd/PSDLoader.cpp b/src/add-ons/translators/psd/PSDLoader.cpp new file mode 100644 index 0000000000..ee0c265411 --- /dev/null +++ b/src/add-ons/translators/psd/PSDLoader.cpp @@ -0,0 +1,228 @@ +/* + * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "PSDLoader.h" +#include "BaseTranslator.h" + + +PSDLoader::PSDLoader(BPositionIO *src) +{ + fLoaded = false; + fStream = src; + + fStream->Seek(0, SEEK_END); + fStreamSize = fStream->Position(); + fStream->Seek(0, SEEK_SET); + + if (fStreamSize <= 0) + return; + + fStream->Seek(0, SEEK_SET); + + fSignature = GetInt32FromStream(fStream); + if (fSignature != 0x38425053) + return; + + fVersion = GetInt16FromStream(fStream); + + //Skip reserved data + SkipStreamBlock(fStream, 6); + + fChannels = GetInt16FromStream(fStream); + fHeight = GetInt32FromStream(fStream); + fWidth = GetInt32FromStream(fStream); + fDepth = GetInt16FromStream(fStream); + fColorFormat = GetInt16FromStream(fStream); + + //Skip mode data + SkipStreamBlock(fStream, GetInt32FromStream(fStream)); + //Skip image resources + SkipStreamBlock(fStream, GetInt32FromStream(fStream)); + //Skip reserved data + SkipStreamBlock(fStream, GetInt32FromStream(fStream)); + + fCompression = GetInt16FromStream(fStream); + + fStreamPos = fStream->Position(); + + fLoaded = true; +} + + +PSDLoader::~PSDLoader() +{ +} + + +bool +PSDLoader::IsLoaded(void) +{ + return fLoaded; +} + + +bool +PSDLoader::IsSupported(void) +{ + if (!fLoaded) + return false; + + if (fVersion != 1) + return false; + + if (fChannels < 0 || fChannels > 16) + return false; + + if (fDepth != 8) + return false; + + if (fColorFormat != 3) + return false; + + if (fCompression != PSD_COMPRESSED_RAW && + fCompression != PSD_COMPRESSED_RLE) + return false; + + return true; +} + + +int +PSDLoader::Decode(BPositionIO *target) +{ + if(!IsSupported()) + return B_NO_TRANSLATOR; + + fStreamBuffer = new uint8[fStreamSize]; + fStream->Seek(0, SEEK_SET); + fStream->Read(fStreamBuffer, fStreamSize); + + uint8 *imageData = new uint8[fWidth * fHeight * sizeof(uint32)]; + + int pixelCount = fWidth * fHeight; + + //RGBA to BRGA order mapping table + int channelMap[4] = {2, 1, 0, 3}; + + if (fCompression == PSD_COMPRESSED_RAW) { + for (int channelIdx = 0; channelIdx < 4; channelIdx++) { + uint8 *ptr = imageData + channelMap[channelIdx]; + if (channelIdx > fChannels) { + for (int i = 0; i < pixelCount; i++, ptr += 4) + *ptr = (channelIdx == 3) ? 255 : 0; + } else { + for (int i = 0; i < pixelCount; i++, ptr += 4) + *ptr = (uint8)fStreamBuffer[fStreamPos++]; + } + } + } + + if (fCompression == PSD_COMPRESSED_RLE) { + fStreamPos += fHeight * fChannels * 2; + + for (int channelIdx = 0; channelIdx < 4; channelIdx++) { + uint8 *ptr = imageData + channelMap[channelIdx]; + + if (channelIdx >= fChannels) { + for (int i = 0; i < pixelCount; i++, ptr += 4) + *ptr = (channelIdx == 3 ? 255 : 0); + } else { + // Read the RLE data. + int count = 0; + while (count < pixelCount) { + uint8 len = (uint8)fStreamBuffer[fStreamPos++]; + if (len == 128) { + continue; + } else if (len < 128) { + len++; + count += len; + while (len) { + *ptr = (int8)fStreamBuffer[fStreamPos++]; + ptr += 4; + len--; + } + } else if (len > 128) { + int8 val = (int8)fStreamBuffer[fStreamPos++]; + len ^= 255; + len += 2; + count += len; + while (len) { + *ptr = val; + ptr += 4; + len--; + } + } + } + } + } + } + + TranslatorBitmap bitsHeader; + bitsHeader.magic = B_TRANSLATOR_BITMAP; + bitsHeader.bounds.left = 0; + bitsHeader.bounds.top = 0; + bitsHeader.bounds.right = fWidth - 1; + bitsHeader.bounds.bottom = fHeight - 1; + bitsHeader.rowBytes = sizeof(uint32) * fWidth; + bitsHeader.colors = B_RGBA32; + bitsHeader.dataSize = bitsHeader.rowBytes * fHeight; + + if (swap_data(B_UINT32_TYPE, &bitsHeader, + sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) { + return B_NO_TRANSLATOR; + } + + target->Write(&bitsHeader, sizeof(TranslatorBitmap)); + target->Write(imageData, fHeight * fWidth * sizeof(uint32)); + + delete imageData; + delete fStreamBuffer; + + return B_OK; +} + + +int32 +PSDLoader::GetInt32FromStream(BPositionIO *in) +{ + int32 ret; + in->Read(&ret, sizeof(int32)); + return B_BENDIAN_TO_HOST_INT32(ret); +} + + +int16 +PSDLoader::GetInt16FromStream(BPositionIO *in) +{ + int16 ret; + in->Read(&ret, sizeof(int16)); + return B_BENDIAN_TO_HOST_INT16(ret); +} + + +int8 +PSDLoader::GetInt8FromStream(BPositionIO *in) +{ + int8 ret; + in->Read(&ret, sizeof(int8)); + return ret; +} + + +uint8 +PSDLoader::GetUInt8FromStream(BPositionIO *in) +{ + uint8 ret; + in->Read(&ret, sizeof(uint8)); + return ret; +} + + +void +PSDLoader::SkipStreamBlock(BPositionIO *in, size_t count) +{ + in->Seek(count, SEEK_CUR); +} diff --git a/src/add-ons/translators/psd/PSDLoader.h b/src/add-ons/translators/psd/PSDLoader.h new file mode 100644 index 0000000000..5207e227ef --- /dev/null +++ b/src/add-ons/translators/psd/PSDLoader.h @@ -0,0 +1,61 @@ +/* + * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#ifndef PSD_LOADER_H +#define PSD_LOADER_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PSD_COMPRESSED_RAW 0 +#define PSD_COMPRESSED_RLE 1 + +class PSDLoader { +public: + PSDLoader(BPositionIO *stream); + ~PSDLoader(); + + int Decode(BPositionIO *target); + bool IsLoaded(void); + bool IsSupported(void); + +private: + int32 GetInt32FromStream(BPositionIO *in); + int16 GetInt16FromStream(BPositionIO *in); + uint8 GetUInt8FromStream(BPositionIO *in); + int8 GetInt8FromStream(BPositionIO *in); + void SkipStreamBlock(BPositionIO *in, size_t count); + + BPositionIO *fStream; + uint8 *fStreamBuffer; + size_t fStreamSize; + size_t fStreamPos; + + int32 fSignature; + int16 fVersion; + int16 fChannels; + int32 fHeight; + int32 fWidth; + int16 fDepth; + int16 fColorFormat; + int16 fCompression; + + bool fLoaded; +}; + + +#endif /* PSD_LOADER_H */ diff --git a/src/add-ons/translators/psd/PSDTranslator.cpp b/src/add-ons/translators/psd/PSDTranslator.cpp new file mode 100644 index 0000000000..2a89abd682 --- /dev/null +++ b/src/add-ons/translators/psd/PSDTranslator.cpp @@ -0,0 +1,147 @@ +/* + * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include + +#include "ConfigView.h" +#include "PSDTranslator.h" +#include "PSDLoader.h" + +const char *kDocumentCount = "/documentCount"; +const char *kDocumentIndex = "/documentIndex"; + +#define kPSDMimeType "image/vnd.adobe.photoshop" +#define kPSDName "Photoshop image" + +static const translation_format sInputFormats[] = { + { + PSD_IMAGE_FORMAT, + B_TRANSLATOR_BITMAP, + PSD_IN_QUALITY, + PSD_IN_CAPABILITY, + kPSDMimeType, + kPSDName + }, +}; + +static const translation_format sOutputFormats[] = { + { + B_TRANSLATOR_BITMAP, + B_TRANSLATOR_BITMAP, + BITS_OUT_QUALITY, + BITS_OUT_CAPABILITY, + "image/x-be-bitmap", + "Be Bitmap Format (PSDTranslator)" + }, +}; + + +static const TranSetting sDefaultSettings[] = { + {B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false}, + {B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false} +}; + +const uint32 kNumInputFormats = 1; +const uint32 kNumOutputFormats = 1; +const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) + / sizeof(TranSetting); + + +PSDTranslator::PSDTranslator() + : BaseTranslator(kPSDName, + "Photoshop image translator", + PSD_TRANSLATOR_VERSION, + sInputFormats, kNumInputFormats, + sOutputFormats, kNumOutputFormats, + "PSDTranslator", + sDefaultSettings, kNumDefaultSettings, + B_TRANSLATOR_BITMAP, PSD_IMAGE_FORMAT) +{ +} + + +PSDTranslator::~PSDTranslator() +{ +} + + +status_t +PSDTranslator::DerivedIdentify(BPositionIO *stream, + const translation_format *format, BMessage *ioExtension, + translator_info *info, uint32 outType) +{ + if (!outType) + outType = B_TRANSLATOR_BITMAP; + if (outType != B_TRANSLATOR_BITMAP && outType != PSD_IMAGE_FORMAT) + return B_NO_TRANSLATOR; + + PSDLoader psdFile(stream); + if (!psdFile.IsSupported()) + return B_ILLEGAL_DATA; + + info->type = PSD_IMAGE_FORMAT; + info->group = B_TRANSLATOR_BITMAP; + info->quality = PSD_IN_QUALITY; + info->capability = PSD_IN_CAPABILITY; + strcpy(info->name, kPSDName); + strcpy(info->MIME, kPSDMimeType); + + return B_OK; +} + + +status_t +PSDTranslator::DerivedTranslate(BPositionIO *source, + const translator_info *info, BMessage *ioExtension, + uint32 outType, BPositionIO *target, int32 baseType) +{ + if (outType != B_TRANSLATOR_BITMAP) + return B_NO_TRANSLATOR; + + switch (baseType) { + case 0: + { + if (outType != B_TRANSLATOR_BITMAP) + return B_NO_TRANSLATOR; + + PSDLoader psdFile(source); + if (!psdFile.IsLoaded()) + return B_NO_TRANSLATOR; + + return psdFile.Decode(target); + } + + default: + return B_NO_TRANSLATOR; + } +} + + +status_t +PSDTranslator::DerivedCanHandleImageSize(float width, float height) const +{ + return B_OK; +} + + +BView * +PSDTranslator::NewConfigView(TranslatorSettings *settings) +{ + return new ConfigView(settings); +} + + +BTranslator * +make_nth_translator(int32 n, image_id you, uint32 flags, ...) +{ + if (n != 0) + return NULL; + + return new PSDTranslator(); +} + diff --git a/src/add-ons/translators/psd/PSDTranslator.h b/src/add-ons/translators/psd/PSDTranslator.h new file mode 100644 index 0000000000..2134bee95d --- /dev/null +++ b/src/add-ons/translators/psd/PSDTranslator.h @@ -0,0 +1,56 @@ +/* + * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#ifndef PSD_TRANSLATOR_H +#define PSD_TRANSLATOR_H + +#include "BaseTranslator.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DOCUMENT_COUNT "/documentCount" +#define DOCUMENT_INDEX "/documentIndex" + +#define PSD_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(1, 0, 0) +#define PSD_IMAGE_FORMAT 'PSD ' + +#define PSD_IN_QUALITY 0.5 +#define PSD_IN_CAPABILITY 0.5 +#define BITS_OUT_QUALITY 1 +#define BITS_OUT_CAPABILITY 0.9 + +class PSDTranslator : public BaseTranslator { + public: + PSDTranslator(); + + virtual status_t DerivedIdentify(BPositionIO *inSource, + const translation_format *inFormat, BMessage *ioExtension, + translator_info *outInfo, uint32 outType); + + virtual status_t DerivedTranslate(BPositionIO *inSource, + const translator_info *inInfo, BMessage *ioExtension, + uint32 outType, BPositionIO *outDestination, int32 baseType); + + virtual status_t DerivedCanHandleImageSize(float width, + float height) const; + + virtual BView *NewConfigView(TranslatorSettings *settings); + + protected: + virtual ~PSDTranslator(); +}; + +extern const char *kDocumentCount; +extern const char *kDocumentIndex; + +#endif /* PSD_TRANSLATOR_H */ diff --git a/src/add-ons/translators/psd/PSDTranslator.rdef b/src/add-ons/translators/psd/PSDTranslator.rdef new file mode 100644 index 0000000000..32de17526d --- /dev/null +++ b/src/add-ons/translators/psd/PSDTranslator.rdef @@ -0,0 +1,15 @@ +/* + * PSDTranslator.rdef + */ + +resource app_signature "application/x-vnd.Haiku-PSDTranslator"; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + variety = 0, + internal = 0, + short_info = "1.0.0", + long_info = "Haiku PSDTranslator Add-Ons." +}; diff --git a/src/add-ons/translators/psd/PSDTranslatorApp.cpp b/src/add-ons/translators/psd/PSDTranslatorApp.cpp new file mode 100644 index 0000000000..496657f6ac --- /dev/null +++ b/src/add-ons/translators/psd/PSDTranslatorApp.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#include + +#include "PSDTranslator.h" +#include "TranslatorWindow.h" + +int +main(int argc, char *argv[]) +{ + BApplication application("application/x-vnd.Haiku-PSDTranslator"); + + status_t result; + result = LaunchTranslatorWindow(new PSDTranslator, "PSD Settings", + BRect(0, 0, 320, 200)); + if (result != B_OK) + return 1; + + application.Run(); + + return 0; +}