/src/imagemagick/coders/pgx.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % PPPP GGGG X X % |
7 | | % P P G X X % |
8 | | % PPPP G GG X % |
9 | | % P G G X X % |
10 | | % P GGG X X % |
11 | | % % |
12 | | % % |
13 | | % PGX JPEG 2000 Format % |
14 | | % % |
15 | | % Software Design % |
16 | | % Cristy % |
17 | | % July 2016 % |
18 | | % % |
19 | | % % |
20 | | % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization % |
21 | | % dedicated to making software imaging solutions freely available. % |
22 | | % % |
23 | | % You may not use this file except in compliance with the License. You may % |
24 | | % obtain a copy of the License at % |
25 | | % % |
26 | | % https://imagemagick.org/license/ % |
27 | | % % |
28 | | % Unless required by applicable law or agreed to in writing, software % |
29 | | % distributed under the License is distributed on an "AS IS" BASIS, % |
30 | | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
31 | | % See the License for the specific language governing permissions and % |
32 | | % limitations under the License. % |
33 | | % % |
34 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
35 | | % |
36 | | % |
37 | | */ |
38 | | |
39 | | /* |
40 | | Include declarations. |
41 | | */ |
42 | | #include "MagickCore/studio.h" |
43 | | #include "MagickCore/attribute.h" |
44 | | #include "MagickCore/blob.h" |
45 | | #include "MagickCore/blob-private.h" |
46 | | #include "MagickCore/cache.h" |
47 | | #include "MagickCore/color-private.h" |
48 | | #include "MagickCore/colormap.h" |
49 | | #include "MagickCore/colorspace.h" |
50 | | #include "MagickCore/colorspace-private.h" |
51 | | #include "MagickCore/exception.h" |
52 | | #include "MagickCore/exception-private.h" |
53 | | #include "MagickCore/image.h" |
54 | | #include "MagickCore/image-private.h" |
55 | | #include "MagickCore/list.h" |
56 | | #include "MagickCore/magick.h" |
57 | | #include "MagickCore/memory_.h" |
58 | | #include "MagickCore/monitor.h" |
59 | | #include "MagickCore/monitor-private.h" |
60 | | #include "MagickCore/quantum-private.h" |
61 | | #include "MagickCore/static.h" |
62 | | #include "MagickCore/string_.h" |
63 | | #include "MagickCore/string-private.h" |
64 | | #include "MagickCore/module.h" |
65 | | |
66 | | /* |
67 | | Forward declarations. |
68 | | */ |
69 | | static MagickBooleanType |
70 | | WritePGXImage(const ImageInfo *,Image *,ExceptionInfo *); |
71 | | |
72 | | /* |
73 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
74 | | % % |
75 | | % % |
76 | | % % |
77 | | % I s P G X % |
78 | | % % |
79 | | % % |
80 | | % % |
81 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
82 | | % |
83 | | % IsPGXreturns True if the image format type, identified by the magick |
84 | | % string, is PGX. |
85 | | % |
86 | | % The format of the IsPGX method is: |
87 | | % |
88 | | % unsigned int IsPGX(const unsigned char *magick,const size_t length) |
89 | | % |
90 | | % A description of each parameter follows: |
91 | | % |
92 | | % o magick: compare image format pattern against these bytes. |
93 | | % |
94 | | % o length: Specifies the length of the magick string. |
95 | | % |
96 | | */ |
97 | | static unsigned int IsPGX(const unsigned char *magick,const size_t length) |
98 | 0 | { |
99 | 0 | if (length < 5) |
100 | 0 | return(MagickFalse); |
101 | 0 | if ((memcmp(magick,"PG ML",5) == 0) || (memcmp(magick,"PG LM",5) == 0)) |
102 | 0 | return(MagickTrue); |
103 | 0 | return(MagickFalse); |
104 | 0 | } |
105 | | |
106 | | /* |
107 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
108 | | % % |
109 | | % % |
110 | | % % |
111 | | % R e a d P G X I m a g e % |
112 | | % % |
113 | | % % |
114 | | % % |
115 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
116 | | % |
117 | | % ReadPGXImage() reads an image of raw bits in LSB order and returns it. |
118 | | % It allocates the memory necessary for the new Image structure and returns |
119 | | % a pointer to the new image. |
120 | | % |
121 | | % The format of the ReadPGXImage method is: |
122 | | % |
123 | | % Image *ReadPGXImage(const ImageInfo *image_info, |
124 | | % ExceptionInfo *exception) |
125 | | % |
126 | | % A description of each parameter follows: |
127 | | % |
128 | | % o image_info: the image info. |
129 | | % |
130 | | % o exception: return any errors or warnings in this structure. |
131 | | % |
132 | | */ |
133 | | static Image *ReadPGXImage(const ImageInfo *image_info,ExceptionInfo *exception) |
134 | 1.25k | { |
135 | 1.25k | char |
136 | 1.25k | buffer[MagickPathExtent], |
137 | 1.25k | endian[MagickPathExtent], |
138 | 1.25k | sans[MagickPathExtent], |
139 | 1.25k | sign[MagickPathExtent]; |
140 | | |
141 | 1.25k | Image |
142 | 1.25k | *image; |
143 | | |
144 | 1.25k | int |
145 | 1.25k | height, |
146 | 1.25k | precision, |
147 | 1.25k | width; |
148 | | |
149 | 1.25k | QuantumInfo |
150 | 1.25k | *quantum_info; |
151 | | |
152 | 1.25k | MagickBooleanType |
153 | 1.25k | status; |
154 | | |
155 | 1.25k | size_t |
156 | 1.25k | length; |
157 | | |
158 | 1.25k | ssize_t |
159 | 1.25k | count, |
160 | 1.25k | y; |
161 | | |
162 | 1.25k | unsigned char |
163 | 1.25k | *pixels; |
164 | | |
165 | | /* |
166 | | Open image file. |
167 | | */ |
168 | 1.25k | assert(image_info != (const ImageInfo *) NULL); |
169 | 1.25k | assert(image_info->signature == MagickCoreSignature); |
170 | 1.25k | assert(exception != (ExceptionInfo *) NULL); |
171 | 1.25k | assert(exception->signature == MagickCoreSignature); |
172 | 1.25k | if (IsEventLogging() != MagickFalse) |
173 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
174 | 0 | image_info->filename); |
175 | 1.25k | image=AcquireImage(image_info,exception); |
176 | 1.25k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
177 | 1.25k | if (status == MagickFalse) |
178 | 0 | { |
179 | 0 | image=DestroyImageList(image); |
180 | 0 | return((Image *) NULL); |
181 | 0 | } |
182 | 1.25k | if (ReadBlobString(image,buffer) == (char *) NULL) |
183 | 1.24k | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
184 | 1.24k | count=(ssize_t) MagickSscanf(buffer,"PG%[ \t]%2s%[ \t+-]%d%[ \t]%d%[ \t]%d", |
185 | 1.24k | sans,endian,sign,&precision,sans,&width,sans,&height); |
186 | 1.24k | if (count != 8) |
187 | 1.21k | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
188 | 1.21k | image->depth=(size_t) precision; |
189 | 1.21k | if (LocaleCompare(endian,"ML") == 0) |
190 | 4 | image->endian=MSBEndian; |
191 | 1.21k | image->columns=(size_t) width; |
192 | 1.21k | image->rows=(size_t) height; |
193 | 1.21k | if ((image->columns == 0) || (image->rows == 0)) |
194 | 1.20k | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
195 | 1.20k | if (image_info->ping != MagickFalse) |
196 | 1 | { |
197 | 1 | (void) CloseBlob(image); |
198 | 1 | return(GetFirstImageInList(image)); |
199 | 1 | } |
200 | 1.20k | status=SetImageExtent(image,image->columns,image->rows,exception); |
201 | 1.20k | if (status == MagickFalse) |
202 | 200 | return(DestroyImageList(image)); |
203 | | /* |
204 | | Convert PGX image. |
205 | | */ |
206 | 1.00k | (void) SetImageColorspace(image,GRAYColorspace,exception); |
207 | 1.00k | quantum_info=AcquireQuantumInfo(image_info,image); |
208 | 1.00k | if (quantum_info == (QuantumInfo *) NULL) |
209 | 1.00k | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
210 | 1.00k | length=GetQuantumExtent(image,quantum_info,GrayQuantum); |
211 | 1.00k | pixels=GetQuantumPixels(quantum_info); |
212 | 43.1k | for (y=0; y < (ssize_t) image->rows; y++) |
213 | 42.5k | { |
214 | 42.5k | const void |
215 | 42.5k | *stream; |
216 | | |
217 | 42.5k | Quantum |
218 | 42.5k | *magick_restrict q; |
219 | | |
220 | 42.5k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
221 | 42.5k | if (q == (Quantum *) NULL) |
222 | 0 | break; |
223 | 42.5k | stream=ReadBlobStream(image,length,pixels,&count); |
224 | 42.5k | if (count != (ssize_t) length) |
225 | 382 | break; |
226 | 42.1k | (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, |
227 | 42.1k | GrayQuantum,(unsigned char *) stream,exception); |
228 | 42.1k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
229 | 0 | break; |
230 | 42.1k | if (SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,image->rows) == MagickFalse) |
231 | 0 | break; |
232 | 42.1k | } |
233 | 1.00k | SetQuantumImageType(image,GrayQuantum); |
234 | 1.00k | quantum_info=DestroyQuantumInfo(quantum_info); |
235 | 1.00k | if (EOFBlob(image) != MagickFalse) |
236 | 382 | ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", |
237 | 1.00k | image->filename); |
238 | 1.00k | if (CloseBlob(image) == MagickFalse) |
239 | 0 | status=MagickFalse; |
240 | 1.00k | if (status == MagickFalse) |
241 | 0 | return(DestroyImageList(image)); |
242 | 1.00k | return(GetFirstImageInList(image)); |
243 | 1.00k | } |
244 | | |
245 | | /* |
246 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
247 | | % % |
248 | | % % |
249 | | % % |
250 | | % R e g i s t e r P G X I m a g e % |
251 | | % % |
252 | | % % |
253 | | % % |
254 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
255 | | % |
256 | | % RegisterPGXImage() adds attributes for the PGX image format to |
257 | | % the list of supported formats. The attributes include the image format |
258 | | % tag, a method to read and/or write the format, whether the format |
259 | | % supports the saving of more than one frame to the same file or blob, |
260 | | % whether the format supports native in-memory I/O, and a brief |
261 | | % description of the format. |
262 | | % |
263 | | % The format of the RegisterPGXImage method is: |
264 | | % |
265 | | % size_t RegisterPGXImage(void) |
266 | | % |
267 | | */ |
268 | | ModuleExport size_t RegisterPGXImage(void) |
269 | 9 | { |
270 | 9 | MagickInfo |
271 | 9 | *entry; |
272 | | |
273 | 9 | entry=AcquireMagickInfo("PGX","PGX","JPEG 2000 uncompressed format"); |
274 | 9 | entry->decoder=(DecodeImageHandler *) ReadPGXImage; |
275 | 9 | entry->encoder=(EncodeImageHandler *) WritePGXImage; |
276 | 9 | entry->magick=(IsImageFormatHandler *) IsPGX; |
277 | 9 | entry->flags^=CoderAdjoinFlag; |
278 | 9 | entry->flags^=CoderUseExtensionFlag; |
279 | 9 | (void) RegisterMagickInfo(entry); |
280 | 9 | return(MagickImageCoderSignature); |
281 | 9 | } |
282 | | |
283 | | /* |
284 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
285 | | % % |
286 | | % % |
287 | | % % |
288 | | % U n r e g i s t e r P G X I m a g e % |
289 | | % % |
290 | | % % |
291 | | % % |
292 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
293 | | % |
294 | | % UnregisterPGXImage() removes format registrations made by the |
295 | | % PGX module from the list of supported formats. |
296 | | % |
297 | | % The format of the UnregisterPGXImage method is: |
298 | | % |
299 | | % UnregisterPGXImage(void) |
300 | | % |
301 | | */ |
302 | | ModuleExport void UnregisterPGXImage(void) |
303 | 0 | { |
304 | 0 | (void) UnregisterMagickInfo("PGX"); |
305 | 0 | } |
306 | | |
307 | | /* |
308 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
309 | | % % |
310 | | % % |
311 | | % % |
312 | | % W r i t e P G X I m a g e % |
313 | | % % |
314 | | % % |
315 | | % % |
316 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
317 | | % |
318 | | % WritePGXImage() writes an image of raw bits in LSB order to a file. |
319 | | % |
320 | | % The format of the WritePGXImage method is: |
321 | | % |
322 | | % MagickBooleanType WritePGXImage(const ImageInfo *image_info, |
323 | | % Image *image,ExceptionInfo *exception) |
324 | | % |
325 | | % A description of each parameter follows. |
326 | | % |
327 | | % o image_info: the image info. |
328 | | % |
329 | | % o image: The image. |
330 | | % |
331 | | % o exception: return any errors or warnings in this structure. |
332 | | % |
333 | | */ |
334 | | static MagickBooleanType WritePGXImage(const ImageInfo *image_info,Image *image, |
335 | | ExceptionInfo *exception) |
336 | 623 | { |
337 | 623 | char |
338 | 623 | buffer[MagickPathExtent]; |
339 | | |
340 | 623 | MagickBooleanType |
341 | 623 | status; |
342 | | |
343 | 623 | QuantumInfo |
344 | 623 | *quantum_info; |
345 | | |
346 | 623 | const Quantum |
347 | 623 | *p; |
348 | | |
349 | 623 | size_t |
350 | 623 | length; |
351 | | |
352 | 623 | ssize_t |
353 | 623 | count, |
354 | 623 | y; |
355 | | |
356 | 623 | unsigned char |
357 | 623 | *pixels; |
358 | | |
359 | | /* |
360 | | Open output image file. |
361 | | */ |
362 | 623 | assert(image_info != (const ImageInfo *) NULL); |
363 | 623 | assert(image_info->signature == MagickCoreSignature); |
364 | 623 | assert(image != (Image *) NULL); |
365 | 623 | assert(image->signature == MagickCoreSignature); |
366 | 623 | assert(exception != (ExceptionInfo *) NULL); |
367 | 623 | assert(exception->signature == MagickCoreSignature); |
368 | 623 | if (IsEventLogging() != MagickFalse) |
369 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
370 | 623 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
371 | 623 | if (status == MagickFalse) |
372 | 0 | return(status); |
373 | 623 | (void) FormatLocaleString(buffer,MagickPathExtent,"PG ML + %g %g %g\n", |
374 | 623 | (double) image->depth,(double) image->columns,(double) image->rows); |
375 | 623 | (void) WriteBlob(image,strlen(buffer),(unsigned char *) buffer); |
376 | 623 | if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) |
377 | 0 | (void) TransformImageColorspace(image,sRGBColorspace,exception); |
378 | 623 | quantum_info=AcquireQuantumInfo(image_info,image); |
379 | 623 | if (quantum_info == (QuantumInfo *) NULL) |
380 | 623 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
381 | 623 | pixels=(unsigned char *) GetQuantumPixels(quantum_info); |
382 | 32.5k | for (y=0; y < (ssize_t) image->rows; y++) |
383 | 31.9k | { |
384 | 31.9k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
385 | 31.9k | if (p == (const Quantum *) NULL) |
386 | 0 | break; |
387 | 31.9k | length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info, |
388 | 31.9k | GrayQuantum,pixels,exception); |
389 | 31.9k | count=WriteBlob(image,length,pixels); |
390 | 31.9k | if (count != (ssize_t) length) |
391 | 0 | break; |
392 | 31.9k | count=WriteBlob(image,(size_t) (-(ssize_t) length) & 0x01,pixels); |
393 | 31.9k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, |
394 | 31.9k | image->rows); |
395 | 31.9k | if (status == MagickFalse) |
396 | 0 | break; |
397 | 31.9k | } |
398 | 623 | quantum_info=DestroyQuantumInfo(quantum_info); |
399 | 623 | if (y < (ssize_t) image->rows) |
400 | 623 | ThrowWriterException(CorruptImageError,"UnableToWriteImageData"); |
401 | 623 | if (CloseBlob(image) == MagickFalse) |
402 | 0 | status=MagickFalse; |
403 | 623 | return(status); |
404 | 623 | } |