comparison Core/Images/PamWriter.cpp @ 2705:5c18a22cb981

fix portability of PAM reader/writer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 06 Jul 2018 16:33:03 +0200
parents f77c7b48f798
children 6356e2ceb493
comparison
equal deleted inserted replaced
2704:b71c59312bae 2705:5c18a22cb981
32 32
33 33
34 #include "../PrecompiledHeaders.h" 34 #include "../PrecompiledHeaders.h"
35 #include "PamWriter.h" 35 #include "PamWriter.h"
36 36
37 #include "../ChunkedBuffer.h"
38 #include "../Endianness.h" 37 #include "../Endianness.h"
39 #include "../OrthancException.h" 38 #include "../OrthancException.h"
40 #include "../Toolbox.h" 39 #include "../Toolbox.h"
41 40
42 #include <vector> 41 #include <boost/lexical_cast.hpp>
43 #include <stdint.h>
44 #include <iostream>
45 #include <sstream>
46 #include <fstream>
47
48 #if ORTHANC_SANDBOXED == 0
49 # include "../SystemToolbox.h"
50 #endif
51 42
52 43
53 namespace Orthanc 44 namespace Orthanc
54 { 45 {
55 namespace 46 static void GetPixelFormatInfo(const PixelFormat& format,
47 unsigned int& maxValue,
48 unsigned int& channelCount,
49 unsigned int& bytesPerChannel,
50 std::string& tupleType)
56 { 51 {
57 void GetPixelFormatInfo(const PixelFormat& format, unsigned int& maxValue, unsigned int& channelCount, unsigned int& bytesPerChannel, const char*& tupleType) { 52 switch (format)
58 maxValue = 255; 53 {
59 channelCount = 1;
60 bytesPerChannel = 1;
61 tupleType = NULL;
62
63 switch (format) {
64 case PixelFormat_Grayscale8: 54 case PixelFormat_Grayscale8:
65 maxValue = 255; 55 maxValue = 255;
66 channelCount = 1; 56 channelCount = 1;
67 bytesPerChannel = 1; 57 bytesPerChannel = 1;
68 tupleType = "GRAYSCALE"; 58 tupleType = "GRAYSCALE";
69 break; 59 break;
60
70 case PixelFormat_Grayscale16: 61 case PixelFormat_Grayscale16:
71 maxValue = 65535; 62 maxValue = 65535;
72 channelCount = 1; 63 channelCount = 1;
73 bytesPerChannel = 2; 64 bytesPerChannel = 2;
74 tupleType = "GRAYSCALE"; 65 tupleType = "GRAYSCALE";
75 break; 66 break;
67
76 case PixelFormat_RGB24: 68 case PixelFormat_RGB24:
77 maxValue = 255; 69 maxValue = 255;
78 channelCount = 3; 70 channelCount = 3;
79 bytesPerChannel = 1; 71 bytesPerChannel = 1;
80 tupleType = "RGB"; 72 tupleType = "RGB";
81 break; 73 break;
74
82 case PixelFormat_RGB48: 75 case PixelFormat_RGB48:
83 maxValue = 255; 76 maxValue = 255;
84 channelCount = 3; 77 channelCount = 3;
85 bytesPerChannel = 2; 78 bytesPerChannel = 2;
86 tupleType = "RGB"; 79 tupleType = "RGB";
87 break; 80 break;
81
88 default: 82 default:
89 throw OrthancException(ErrorCode_NotImplemented); 83 throw OrthancException(ErrorCode_NotImplemented);
90 }
91
92 } 84 }
93
94 void WriteToStream(std::ostream& output,
95 unsigned int width,
96 unsigned int height,
97 unsigned int pitch,
98 PixelFormat format,
99 const void* buffer)
100 {
101 unsigned int maxValue = 255;
102 unsigned int channelCount = 1;
103 unsigned int bytesPerChannel = 1;
104 const char* tupleType = "GRAYSCALE";
105 GetPixelFormatInfo(format, maxValue, channelCount, bytesPerChannel, tupleType);
106
107 output << "P7" << "\n";
108 output << "WIDTH " << width << "\n";
109 output << "HEIGHT " << height << "\n";
110 output << "DEPTH " << channelCount << "\n";
111 output << "MAXVAL " << maxValue << "\n";
112 output << "TUPLTYPE " << tupleType << "\n";
113 output << "ENDHDR" << "\n";
114
115 if (Toolbox::DetectEndianness() == Endianness_Little && bytesPerChannel == 2)
116 {
117 uint16_t tmp;
118 const uint16_t* pixel = NULL;
119 for (unsigned int h = 0; h < height; ++h)
120 {
121 pixel = reinterpret_cast<const uint16_t*> (reinterpret_cast<const uint8_t*>(buffer) + h * pitch);
122 for (unsigned int w = 0; w < (width * channelCount); ++w, ++pixel)
123 {
124 tmp = htobe16(*pixel);
125 output.write(reinterpret_cast<const char*>(&tmp), 2);
126 }
127 }
128 }
129 else
130 {
131 for (unsigned int h = 0; h < height; ++h)
132 {
133 output.write(reinterpret_cast<const char*>(reinterpret_cast<const uint8_t*>(buffer) + h * pitch), channelCount * bytesPerChannel * width);
134 }
135 }
136
137 }
138
139 } 85 }
140 86
141 #if ORTHANC_SANDBOXED == 0 87
142 void PamWriter::WriteToFileInternal(const std::string& filename, 88 void PamWriter::WriteToMemoryInternal(std::string& target,
143 unsigned int width,
144 unsigned int height,
145 unsigned int pitch,
146 PixelFormat format,
147 const void* buffer)
148 {
149 std::ofstream outfile (filename, std::ofstream::binary);
150
151 WriteToStream(outfile, width, height, pitch, format, buffer);
152 outfile.close();
153 }
154 #endif
155
156
157 void PamWriter::WriteToMemoryInternal(std::string& output,
158 unsigned int width, 89 unsigned int width,
159 unsigned int height, 90 unsigned int height,
160 unsigned int pitch, 91 unsigned int sourcePitch,
161 PixelFormat format, 92 PixelFormat format,
162 const void* buffer) 93 const void* buffer)
163 { 94 {
164 std::ostringstream outStream; // todo: try to write directly in output and avoid copy 95 unsigned int maxValue, channelCount, bytesPerChannel;
96 std::string tupleType;
97 GetPixelFormatInfo(format, maxValue, channelCount, bytesPerChannel, tupleType);
165 98
166 WriteToStream(outStream, width, height, pitch, format, buffer); 99 target = (std::string("P7") +
167 output = outStream.str(); 100 std::string("\nWIDTH ") + boost::lexical_cast<std::string>(width) +
101 std::string("\nHEIGHT ") + boost::lexical_cast<std::string>(height) +
102 std::string("\nDEPTH ") + boost::lexical_cast<std::string>(channelCount) +
103 std::string("\nMAXVAL ") + boost::lexical_cast<std::string>(maxValue) +
104 std::string("\nTUPLTYPE ") + tupleType +
105 std::string("\nENDHDR\n"));
106
107 if (bytesPerChannel != 1 &&
108 bytesPerChannel != 2)
109 {
110 throw OrthancException(ErrorCode_NotImplemented);
111 }
112
113 size_t targetPitch = channelCount * bytesPerChannel * width;
114 size_t offset = target.size();
115
116 target.resize(offset + targetPitch * height);
117
118 assert(target.size() != 0);
119
120 if (Toolbox::DetectEndianness() == Endianness_Little &&
121 bytesPerChannel == 2)
122 {
123 // Byte swapping
124 for (unsigned int h = 0; h < height; ++h)
125 {
126 const uint16_t* p = reinterpret_cast<const uint16_t*>
127 (reinterpret_cast<const uint8_t*>(buffer) + h * sourcePitch);
128 uint16_t* q = reinterpret_cast<uint16_t*>
129 (reinterpret_cast<uint8_t*>(&target[offset]) + h * targetPitch);
130
131 for (unsigned int w = 0; w < width * channelCount; ++w)
132 {
133 *q = htobe16(*p);
134 p++;
135 q++;
136 }
137 }
138 }
139 else
140 {
141 // Either "bytesPerChannel == 1" (and endianness is not
142 // relevant), or we run on a big endian architecture (and no
143 // byte swapping is necessary, as PAM uses big endian)
144
145 for (unsigned int h = 0; h < height; ++h)
146 {
147 const void* p = reinterpret_cast<const uint8_t*>(buffer) + h * sourcePitch;
148 void* q = reinterpret_cast<uint8_t*>(&target[offset]) + h * targetPitch;
149 memcpy(q, p, targetPitch);
150 }
151 }
168 } 152 }
169 } 153 }