Created
March 15, 2020 07:31
-
-
Save sthairno/4ead1e6446d21a10ee0f95bd1686f870 to your computer and use it in GitHub Desktop.
Siv3D_psd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<Siv3D.hpp> | |
#include"PsdReader.h" | |
void Main() | |
{ | |
Window::Resize(1080, 720); | |
Scene::SetBackground(Palette::White); | |
Size boxSize(5, 5); | |
Texture tex; | |
Image pattern(Scene::Size()); | |
for (int y = 0; y < 150; y++) | |
for (int x = y % 2; x < 240; x += 2) | |
Rect(Point(x, y) * boxSize, boxSize).overwrite(pattern, HSV(0, 0, 0.6)); | |
Texture patternTex(pattern); | |
Font font(10); | |
PsdReader reader; | |
Image image; | |
bool layerFrame = false; | |
bool layerName = false; | |
while (System::Update()) | |
{ | |
if (DragDrop::HasNewFilePaths()) | |
{ | |
ClearPrint(); | |
Stopwatch stw; | |
reader.open(DragDrop::GetDroppedFilePaths()[0].path); | |
stw.start(); | |
image = reader.getImage(); | |
stw.pause(); | |
Print << U"{}ms"_fmt(stw.msF()); | |
tex = Texture(image); | |
} | |
patternTex.draw(); | |
tex.draw(); | |
if (reader.isOpened) | |
{ | |
for (auto& layer : reader.layers) | |
{ | |
if (layerFrame) | |
{ | |
layer.rect.drawFrame(1, Palette::Red); | |
} | |
if (layerName) | |
{ | |
font(layer.name).draw(layer.rect.pos,Palette::Red); | |
} | |
} | |
} | |
SimpleGUI::CheckBox(layerFrame, U"frame", Vec2(5, 5)); | |
SimpleGUI::CheckBox(layerName, U"name", Vec2(5, 45)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "PsdReader.h" | |
// the main include that always needs to be included in every translation unit that uses the PSD library | |
#include "psd_sdk/Psd.h" | |
// for convenience reasons, we directly include the platform header from the PSD library. | |
// we could have just included <Windows.h> as well, but that is unnecessarily big, and triggers lots of warnings. | |
#include "psd_sdk/PsdPlatform.h" | |
// in the sample, we use the provided malloc allocator for all memory allocations. likewise, we also use the provided | |
// native file interface. | |
// in your code, feel free to use whatever allocator you have lying around. | |
#include "psd_sdk/PsdMallocAllocator.h" | |
#include "psd_sdk/PsdNativeFile.h" | |
#include "psd_sdk/PsdDocument.h" | |
#include "psd_sdk/PsdColorMode.h" | |
#include "psd_sdk/PsdLayer.h" | |
#include "psd_sdk/PsdChannel.h" | |
#include "psd_sdk/PsdChannelType.h" | |
#include "psd_sdk/PsdLayerMask.h" | |
#include "psd_sdk/PsdVectorMask.h" | |
#include "psd_sdk/PsdLayerMaskSection.h" | |
#include "psd_sdk/PsdImageDataSection.h" | |
#include "psd_sdk/PsdImageResourcesSection.h" | |
#include "psd_sdk/PsdParseDocument.h" | |
#include "psd_sdk/PsdParseLayerMaskSection.h" | |
#include "psd_sdk/PsdParseImageDataSection.h" | |
#include "psd_sdk/PsdParseImageResourcesSection.h" | |
#include "psd_sdk/PsdLayerCanvasCopy.h" | |
#include "psd_sdk/PsdInterleave.h" | |
#include "psd_sdk/PsdPlanarImage.h" | |
#include "psd_sdk/PsdExport.h" | |
#include "psd_sdk/PsdExportDocument.h" | |
#include "S3DFileReader.h" | |
static const unsigned int CHANNEL_NOT_FOUND = UINT_MAX; | |
unsigned int FindChannel(Layer* layer, int16_t channelType) | |
{ | |
for (unsigned int i = 0; i < layer->channelCount; ++i) | |
{ | |
Channel* channel = &layer->channels[i]; | |
if (channel->data && channel->type == channelType) | |
return i; | |
} | |
return CHANNEL_NOT_FOUND; | |
} | |
template<typename T> | |
Image dataToImage(Size size, T maxValue, void* r, void* g, void* b, void* a = nullptr) | |
{ | |
uint32 mul = 255 / maxValue; | |
T* rp = static_cast<T*>(r), * gp = static_cast<T*>(g), * bp = static_cast<T*>(b), * ap = static_cast<T*>(a); | |
auto img = Image(size); | |
auto data = img.data(); | |
if (a) | |
{ | |
//RGBA | |
for (size_t i = 0; i < size.x * size.y; i++) | |
{ | |
data->r = rp[i] * mul; | |
data->g = gp[i] * mul; | |
data->b = bp[i] * mul; | |
data->a = ap[i] * mul; | |
data++; | |
} | |
} | |
else | |
{ | |
//RGB | |
for (size_t i = 0; i < size.x * size.y; i++) | |
{ | |
data->r = rp[i] * mul; | |
data->g = gp[i] * mul; | |
data->b = bp[i] * mul; | |
data->a = 255; | |
data++; | |
} | |
} | |
return img; | |
} | |
template<typename T> | |
void monoToGrid(Grid<float>& grid, T maxValue, void* mono) | |
{ | |
T* monop = static_cast<T*>(mono); | |
auto size = grid.size(); | |
auto data = grid.data(); | |
for (size_t i = 0; i < size.x * size.y; i++) | |
{ | |
*data = static_cast<float>(monop[i]) / static_cast<float>(maxValue); | |
data++; | |
} | |
} | |
Image gridToImage(Grid<float>& grid) | |
{ | |
return Image::Generate(grid.size(), [grid](Point pos) | |
{ | |
return HSV(0,0,grid[pos]); | |
} | |
); | |
} | |
PsdReader::PsdReader(FilePath path) | |
{ | |
open(path); | |
} | |
PsdReader::PsdReader(IReader& reader) | |
{ | |
open(reader); | |
} | |
void PsdReader::open(FilePath path) | |
{ | |
BinaryReader reader(path); | |
open(reader); | |
reader.close(); | |
} | |
void PsdReader::open(IReader& reader) | |
{ | |
isOpened = false; | |
MallocAllocator allocator; | |
S3DFileReader file = S3DFileReader(reader); | |
if (!reader.isOpened()) | |
{ | |
return; | |
} | |
//�t�@�C���ǂݍ��� | |
Document* document = CreateDocument(&file, &allocator); | |
if (!document) | |
{ | |
file.Close(); | |
return; | |
} | |
docSize = Size(document->width, document->height); | |
docImage = Image(docSize); | |
//(A)RGB�̂ݑΉ� | |
if (document->colorMode != colorMode::RGB) | |
{ | |
DestroyDocument(document, &allocator); | |
file.Close(); | |
return; | |
} | |
//�w�i��ǂݍ��� | |
if (document->imageDataSection.length != 0) | |
{ | |
ImageDataSection* imageData = ParseImageDataSection(document, &file, &allocator); | |
if (imageData) | |
{ | |
const unsigned int imageCount = imageData->imageCount; | |
if (imageCount == 3) | |
{ | |
if (document->bitsPerChannel == 8) | |
{ | |
docImage = dataToImage<uint8>(docSize, UINT8_MAX, imageData->images[0].data, imageData->images[1].data, imageData->images[2].data); | |
} | |
else if (document->bitsPerChannel == 16) | |
{ | |
docImage = dataToImage<uint16>(docSize, UINT16_MAX, imageData->images[0].data, imageData->images[1].data, imageData->images[2].data); | |
} | |
else if (document->bitsPerChannel == 32) | |
{ | |
docImage = dataToImage<float32_t>(docSize, 1, imageData->images[0].data, imageData->images[1].data, imageData->images[2].data); | |
} | |
} | |
else | |
{ | |
if (document->bitsPerChannel == 8) | |
{ | |
docImage = dataToImage<uint8>(docSize, UINT8_MAX, imageData->images[0].data, imageData->images[1].data, imageData->images[2].data, imageData->images[3].data); | |
} | |
else if (document->bitsPerChannel == 16) | |
{ | |
docImage = dataToImage<uint16>(docSize, UINT16_MAX, imageData->images[0].data, imageData->images[1].data, imageData->images[2].data, imageData->images[3].data); | |
} | |
else if (document->bitsPerChannel == 32) | |
{ | |
docImage = dataToImage<float32_t>(docSize, 1, imageData->images[0].data, imageData->images[1].data, imageData->images[2].data, imageData->images[3].data); | |
} | |
} | |
DestroyImageDataSection(imageData, &allocator); | |
} | |
} | |
//�e���C���[��ǂݍ��� | |
LayerMaskSection* layerMaskSection = ParseLayerMaskSection(document, &file, &allocator); | |
if (layerMaskSection) | |
{ | |
layers = Array<PsdLayer>(layerMaskSection->layerCount); | |
rootLayers = Array<size_t>(); | |
for (unsigned int i = 0; i < layerMaskSection->layerCount; ++i) | |
{ | |
PsdLayer* dst = &layers[i]; | |
Layer* src = &layerMaskSection->layers[i]; | |
Rect layerRect(src->left, src->top, src->right - src->left, src->bottom - src->top); | |
dst->rect = layerRect; | |
if (src->parent) | |
{ | |
size_t parentIdx = static_cast<size_t>(src->parent - layerMaskSection->layers); | |
layers[parentIdx].children.push_back(dst); | |
} | |
else | |
{ | |
rootLayers.push_back(i); | |
} | |
dst->isVisible = src->isVisible; | |
dst->name = Unicode::FromUTF16(std::u16string_view((char16_t*)src->utf16Name)); | |
if (src->isVisible) | |
{ | |
ExtractLayer(document, &file, &allocator, src); | |
dst->opacity = src->opacity; | |
const unsigned int indexR = FindChannel(src, channelType::R); | |
const unsigned int indexG = FindChannel(src, channelType::G); | |
const unsigned int indexB = FindChannel(src, channelType::B); | |
const unsigned int indexA = FindChannel(src, channelType::TRANSPARENCY_MASK); | |
unsigned int channelCount = 0u; | |
if ((indexR != CHANNEL_NOT_FOUND) && (indexG != CHANNEL_NOT_FOUND) && (indexB != CHANNEL_NOT_FOUND)) | |
{ | |
channelCount = 3u; | |
if (indexA != CHANNEL_NOT_FOUND) | |
{ | |
channelCount = 4u; | |
} | |
} | |
if (channelCount == 3u) | |
{ | |
if (document->bitsPerChannel == 8) | |
{ | |
dst->image = dataToImage<uint8>(layerRect.size, UINT8_MAX, src->channels[indexR].data, src->channels[indexG].data, src->channels[indexB].data); | |
} | |
else if (document->bitsPerChannel == 16) | |
{ | |
dst->image = dataToImage<uint16>(layerRect.size, UINT16_MAX, src->channels[indexR].data, src->channels[indexG].data, src->channels[indexB].data); | |
} | |
else if (document->bitsPerChannel == 32) | |
{ | |
dst->image = dataToImage<float32_t>(layerRect.size, 1, src->channels[indexR].data, src->channels[indexG].data, src->channels[indexB].data); | |
} | |
} | |
else if (channelCount == 4u) | |
{ | |
if (document->bitsPerChannel == 8) | |
{ | |
dst->image = dataToImage<uint8>(layerRect.size, UINT8_MAX, src->channels[indexR].data, src->channels[indexG].data, src->channels[indexB].data, src->channels[indexA].data); | |
} | |
else if (document->bitsPerChannel == 16) | |
{ | |
dst->image = dataToImage<uint16>(layerRect.size, UINT16_MAX, src->channels[indexR].data, src->channels[indexG].data, src->channels[indexB].data, src->channels[indexA].data); | |
} | |
else if (document->bitsPerChannel == 32) | |
{ | |
dst->image = dataToImage<float32_t>(layerRect.size, 1, src->channels[indexR].data, src->channels[indexG].data, src->channels[indexB].data, src->channels[indexA].data); | |
} | |
} | |
//���C���[�}�X�N | |
if (src->layerMask) | |
{ | |
dst->layerMask.isExists = true; | |
dst->layerMask.rect.x = src->layerMask->right; | |
dst->layerMask.rect.y = src->layerMask->top; | |
dst->layerMask.rect.w = src->layerMask->right - src->layerMask->left; | |
dst->layerMask.rect.h = src->layerMask->bottom - src->layerMask->top; | |
dst->layerMask.density = src->layerMask->density; | |
dst->layerMask.defaultColor = src->layerMask->defaultColor; | |
dst->layerMask.feather = src->layerMask->feather; | |
dst->layerMask.data.resize(dst->layerMask.rect.w, dst->layerMask.rect.h); | |
if (document->bitsPerChannel == 8) | |
{ | |
monoToGrid<uint8>(dst->layerMask.data, UINT8_MAX, src->layerMask->data); | |
} | |
else if (document->bitsPerChannel == 16) | |
{ | |
monoToGrid<uint16>(dst->layerMask.data, UINT16_MAX, src->layerMask->data); | |
} | |
else if (document->bitsPerChannel == 32) | |
{ | |
monoToGrid<float32_t>(dst->layerMask.data, 1, src->layerMask->data); | |
} | |
} | |
//�x�N�^�[�}�X�N | |
if (src->vectorMask) | |
{ | |
dst->vectorMask.isExists = true; | |
dst->vectorMask.rect.x = src->vectorMask->right; | |
dst->vectorMask.rect.y = src->vectorMask->top; | |
dst->vectorMask.rect.w = src->vectorMask->right - src->vectorMask->left; | |
dst->vectorMask.rect.h = src->vectorMask->bottom - src->vectorMask->top; | |
dst->vectorMask.density = src->vectorMask->density; | |
dst->vectorMask.defaultColor = src->vectorMask->defaultColor; | |
dst->vectorMask.feather = src->vectorMask->feather; | |
dst->vectorMask.data.resize(dst->vectorMask.rect.w, dst->vectorMask.rect.h); | |
if (document->bitsPerChannel == 8) | |
{ | |
monoToGrid<uint8>(dst->vectorMask.data, UINT8_MAX, src->vectorMask->data); | |
} | |
else if (document->bitsPerChannel == 16) | |
{ | |
monoToGrid<uint16>(dst->vectorMask.data, UINT16_MAX, src->vectorMask->data); | |
} | |
else if (document->bitsPerChannel == 32) | |
{ | |
monoToGrid<float32_t>(dst->vectorMask.data, 1, src->vectorMask->data); | |
} | |
} | |
} | |
} | |
DestroyLayerMaskSection(layerMaskSection, &allocator); | |
} | |
DestroyDocument(document, &allocator); | |
isOpened = true; | |
} | |
Image PsdReader::getImage() | |
{ | |
if (isOpened) | |
{ | |
Image img(docImage); | |
for (auto& layerIdx : rootLayers) | |
{ | |
layers[layerIdx].overwrite(img); | |
} | |
return img; | |
} | |
else | |
{ | |
return Image(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include<Siv3D.hpp> | |
class PsdLayerMask | |
{ | |
public: | |
bool isExists; | |
Rect rect; | |
Grid<float> data; | |
float feather; | |
uint8 density; | |
uint8 defaultColor; | |
}; | |
class PsdVectorMask | |
{ | |
public: | |
bool isExists; | |
Rect rect; | |
Grid<float> data; | |
float feather; | |
uint8 density; | |
uint8 defaultColor; | |
}; | |
class PsdLayer | |
{ | |
public: | |
bool isVisible; | |
uint8 opacity; | |
Image image; | |
String name; | |
Rect rect; | |
PsdLayerMask layerMask; | |
PsdVectorMask vectorMask; | |
Array<PsdLayer*> children; | |
void overwrite(Image& dst, uint8 opacity = 255, int depth = 0) | |
{ | |
opacity = Clamp<uint8>(opacity, 0, 255); | |
if (isVisible) | |
{ | |
for (int y = 0; y < rect.h; y++) | |
{ | |
for (int x = 0; x < rect.w; x++) | |
{ | |
Point srcPos(x, y); | |
Point dstPos = rect.pos + dstPos; | |
if (0 <= dstPos.x && dstPos.x < dst.width() && | |
0 <= dstPos.y && dstPos.y < dst.height()) | |
{ | |
Color& srcCol = image[srcPos]; | |
Color& dstCol = dst[dstPos]; | |
srcCol.a = srcCol.a * this->opacity * opacity / 65025; | |
dstCol.r = (dstCol.r * (255 - srcCol.a) + srcCol.r * srcCol.a) / 255; | |
dstCol.g = (dstCol.g * (255 - srcCol.a) + srcCol.g * srcCol.a) / 255; | |
dstCol.b = (dstCol.b * (255 - srcCol.a) + srcCol.b * srcCol.a) / 255; | |
dstCol.a = 255 - ((255 - dstCol.a) * (255 - srcCol.a) / 255); | |
} | |
} | |
} | |
for (auto& child : children) | |
{ | |
child->overwrite(dst, this->opacity * opacity / 255, depth + 1); | |
} | |
} | |
} | |
}; | |
class PsdReader | |
{ | |
public: | |
bool isOpened; | |
Size docSize; | |
Image docImage; | |
Array<PsdLayer> layers; | |
Array<size_t> rootLayers; | |
PsdReader() = default; | |
PsdReader(FilePath path); | |
PsdReader(IReader& reader); | |
void open(FilePath path); | |
void open(IReader& reader); | |
Image getImage(); | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "S3DFileReader.h" | |
S3DFileReader::S3DFileReader(IReader& read) : File(&MallocAllocator()), reader(read) | |
{ | |
} | |
bool S3DFileReader::DoOpenRead(const wchar_t* filename) | |
{ | |
return false; | |
} | |
bool S3DFileReader::DoOpenWrite(const wchar_t* filename) | |
{ | |
return false; | |
} | |
bool S3DFileReader::DoClose(void) | |
{ | |
return true; | |
} | |
File::ReadOperation S3DFileReader::DoRead(void* buffer, uint32_t count, uint64_t position) | |
{ | |
reader.read(buffer, static_cast<int64>(position), static_cast<int64>(count)); | |
return static_cast<File::ReadOperation>(NULL); | |
} | |
bool S3DFileReader::DoWaitForRead(File::ReadOperation& operation) | |
{ | |
return true; | |
} | |
File::WriteOperation S3DFileReader::DoWrite(const void* buffer, uint32_t count, uint64_t position) | |
{ | |
return static_cast<File::ReadOperation>(NULL); | |
} | |
bool S3DFileReader::DoWaitForWrite(File::WriteOperation& operation) | |
{ | |
return false; | |
} | |
uint64_t S3DFileReader::DoGetSize(void) const | |
{ | |
return static_cast<uint64_t>(reader.size()); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include<Siv3D.hpp> | |
// the main include that always needs to be included in every translation unit that uses the PSD library | |
#include "psd_sdk/Psd.h" | |
// for convenience reasons, we directly include the platform header from the PSD library. | |
// we could have just included <Windows.h> as well, but that is unnecessarily big, and triggers lots of warnings. | |
#include "psd_sdk/PsdPlatform.h" | |
// in the sample, we use the provided malloc allocator for all memory allocations. likewise, we also use the provided | |
// native file interface. | |
// in your code, feel free to use whatever allocator you have lying around. | |
#include "psd_sdk/PsdMallocAllocator.h" | |
#include "psd_sdk/PsdDocument.h" | |
#include "psd_sdk/PsdColorMode.h" | |
#include "psd_sdk/PsdLayer.h" | |
#include "psd_sdk/PsdChannel.h" | |
#include "psd_sdk/PsdChannelType.h" | |
#include "psd_sdk/PsdLayerMask.h" | |
#include "psd_sdk/PsdVectorMask.h" | |
#include "psd_sdk/PsdLayerMaskSection.h" | |
#include "psd_sdk/PsdImageDataSection.h" | |
#include "psd_sdk/PsdImageResourcesSection.h" | |
#include "psd_sdk/PsdParseDocument.h" | |
#include "psd_sdk/PsdParseLayerMaskSection.h" | |
#include "psd_sdk/PsdParseImageDataSection.h" | |
#include "psd_sdk/PsdParseImageResourcesSection.h" | |
#include "psd_sdk/PsdLayerCanvasCopy.h" | |
#include "psd_sdk/PsdInterleave.h" | |
#include "psd_sdk/PsdPlanarImage.h" | |
#include "psd_sdk/PsdExport.h" | |
#include "psd_sdk/PsdExportDocument.h" | |
#include "psd_sdk/PsdFile.h" | |
PSD_USING_NAMESPACE; | |
/// <summary> | |
/// psd::File��IReader��ϊ�����N���X | |
/// </summary> | |
class S3DFileReader : public File | |
{ | |
public: | |
S3DFileReader(IReader& read); | |
private: | |
virtual bool DoOpenRead(const wchar_t* filename) PSD_OVERRIDE; | |
virtual bool DoOpenWrite(const wchar_t* filename) PSD_OVERRIDE; | |
virtual bool DoClose(void) PSD_OVERRIDE; | |
virtual File::ReadOperation DoRead(void* buffer, uint32_t count, uint64_t position) PSD_OVERRIDE; | |
virtual bool DoWaitForRead(File::ReadOperation& operation) PSD_OVERRIDE; | |
virtual File::WriteOperation DoWrite(const void* buffer, uint32_t count, uint64_t position) PSD_OVERRIDE; | |
virtual bool DoWaitForWrite(File::WriteOperation& operation) PSD_OVERRIDE; | |
virtual uint64_t DoGetSize(void) const PSD_OVERRIDE; | |
IReader& reader; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment