/src/graphicsmagick/coders/uyvy.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2026 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % Copyright 1991-1999 E. I. du Pont de Nemours and Company |
5 | | % SPDX-License-Identifier: MIT |
6 | | % |
7 | | % This program is covered by multiple licenses, which are described in |
8 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
9 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
10 | | % |
11 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
12 | | % % |
13 | | % % |
14 | | % % |
15 | | % U U Y Y V V Y Y % |
16 | | % U U Y Y V V Y Y % |
17 | | % U U Y V V Y % |
18 | | % U U Y V V Y % |
19 | | % UUU Y V Y % |
20 | | % % |
21 | | % % |
22 | | % Read/Write 16bit/pixel Interleaved YUV Image Format. % |
23 | | % % |
24 | | % % |
25 | | % Software Design % |
26 | | % John Cristy % |
27 | | % July 1992 % |
28 | | % % |
29 | | % % |
30 | | % % |
31 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
32 | | % |
33 | | % |
34 | | */ |
35 | | |
36 | | /* |
37 | | Include declarations. |
38 | | */ |
39 | | #include "magick/studio.h" |
40 | | #include "magick/blob.h" |
41 | | #include "magick/pixel_cache.h" |
42 | | #include "magick/magick.h" |
43 | | #include "magick/monitor.h" |
44 | | #include "magick/utility.h" |
45 | | #include "magick/static.h" |
46 | | |
47 | | /* |
48 | | Forward declarations. |
49 | | */ |
50 | | static unsigned int |
51 | | WriteUYVYImage(const ImageInfo *,Image *); |
52 | | |
53 | | /* |
54 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
55 | | % % |
56 | | % % |
57 | | % % |
58 | | % R e a d U Y V Y I m a g e % |
59 | | % % |
60 | | % % |
61 | | % % |
62 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
63 | | % |
64 | | % Method ReadUYVYImage reads an image in the UYVY format and returns it. It |
65 | | % allocates the memory necessary for the new Image structure and returns a |
66 | | % pointer to the new image. |
67 | | % |
68 | | % The format of the ReadUYVYImage method is: |
69 | | % |
70 | | % Image *ReadUYVYImage(const ImageInfo *image_info, |
71 | | % ExceptionInfo *exception) |
72 | | % |
73 | | % A description of each parameter follows: |
74 | | % |
75 | | % o image: Method ReadUYVYImage returns a pointer to the image after |
76 | | % reading. A null image is returned if there is a memory shortage or |
77 | | % if the image cannot be read. |
78 | | % |
79 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
80 | | % |
81 | | % o exception: return any errors or warnings in this structure. |
82 | | % |
83 | | % |
84 | | */ |
85 | | static Image *ReadUYVYImage(const ImageInfo *image_info, |
86 | | ExceptionInfo *exception) |
87 | 49 | { |
88 | 49 | Image |
89 | 49 | *image; |
90 | | |
91 | 49 | long |
92 | 49 | y; |
93 | | |
94 | 49 | register long |
95 | 49 | x; |
96 | | |
97 | 49 | register PixelPacket |
98 | 49 | *q; |
99 | | |
100 | 49 | register long |
101 | 49 | i; |
102 | | |
103 | 49 | unsigned char |
104 | 49 | u, |
105 | 49 | v, |
106 | 49 | y1, |
107 | 49 | y2; |
108 | | |
109 | 49 | unsigned int |
110 | 49 | status; |
111 | | |
112 | | /* |
113 | | Open image file. |
114 | | */ |
115 | 49 | assert(image_info != (const ImageInfo *) NULL); |
116 | 49 | assert(image_info->signature == MagickSignature); |
117 | 49 | assert(exception != (ExceptionInfo *) NULL); |
118 | 49 | assert(exception->signature == MagickSignature); |
119 | 49 | image=AllocateImage(image_info); |
120 | 49 | if ((image->columns == 0) || (image->rows == 0)) |
121 | 49 | ThrowReaderException(OptionError,MustSpecifyImageSize,image); |
122 | 0 | (void) strlcpy(image->filename,image_info->filename,MaxTextExtent); |
123 | 0 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
124 | 0 | if (status == False) |
125 | 0 | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
126 | | /* |
127 | | When subsampling, image width must be evenly divisible by two. |
128 | | */ |
129 | 0 | if (image->columns %2) |
130 | 0 | ThrowReaderException(CorruptImageError,SubsamplingRequiresEvenWidth,image); |
131 | 0 | for (i=0; i < image->offset; i++) |
132 | 0 | { |
133 | 0 | if (EOF == ReadBlobByte(image)) |
134 | 0 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
135 | 0 | image->filename); |
136 | 0 | } |
137 | 0 | image->depth=8; |
138 | 0 | if (image_info->ping) |
139 | 0 | { |
140 | 0 | CloseBlob(image); |
141 | 0 | StopTimer(&image->timer); |
142 | 0 | return(image); |
143 | 0 | } |
144 | | /* |
145 | | Accumulate UYVY, then unpack into two pixels. |
146 | | */ |
147 | 0 | for (y=0; y < (long) image->rows; y++) |
148 | 0 | { |
149 | 0 | q=SetImagePixels(image,0,y,image->columns,1); |
150 | 0 | if (q == (PixelPacket *) NULL) |
151 | 0 | break; |
152 | 0 | for (x=0; x < (long) (image->columns >> 1); x++) |
153 | 0 | { |
154 | 0 | u=ReadBlobByte(image); |
155 | 0 | y1=ReadBlobByte(image); |
156 | 0 | v=ReadBlobByte(image); |
157 | 0 | y2=ReadBlobByte(image); |
158 | 0 | q->red=ScaleCharToQuantum(y1); |
159 | 0 | q->green=ScaleCharToQuantum(u); |
160 | 0 | q->blue=ScaleCharToQuantum(v); |
161 | 0 | q++; |
162 | 0 | q->red=ScaleCharToQuantum(y2); |
163 | 0 | q->green=ScaleCharToQuantum(u); |
164 | 0 | q->blue=ScaleCharToQuantum(v); |
165 | 0 | q++; |
166 | 0 | } |
167 | 0 | if (!SyncImagePixels(image)) |
168 | 0 | break; |
169 | 0 | if (QuantumTick(y,image->rows)) |
170 | 0 | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
171 | 0 | image->filename, |
172 | 0 | image->columns,image->rows)) |
173 | 0 | break; |
174 | 0 | } |
175 | 0 | image->colorspace=YCbCrColorspace; |
176 | 0 | if (TransformColorspace(image,RGBColorspace) == MagickFail) |
177 | 0 | ThrowException(exception,CoderError,UnableToTransformColorspace, |
178 | 0 | image->filename); |
179 | 0 | if (EOFBlob(image)) |
180 | 0 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
181 | 0 | image->filename); |
182 | 0 | CloseBlob(image); |
183 | 0 | StopTimer(&image->timer); |
184 | 0 | return(image); |
185 | 0 | } |
186 | | |
187 | | /* |
188 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
189 | | % % |
190 | | % % |
191 | | % % |
192 | | % R e g i s t e r U Y V Y I m a g e % |
193 | | % % |
194 | | % % |
195 | | % % |
196 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
197 | | % |
198 | | % Method RegisterUYVYImage adds attributes for the UYVY image format to |
199 | | % the list of supported formats. The attributes include the image format |
200 | | % tag, a method to read and/or write the format, whether the format |
201 | | % supports the saving of more than one frame to the same file or blob, |
202 | | % whether the format supports native in-memory I/O, and a brief |
203 | | % description of the format. |
204 | | % |
205 | | % The format of the RegisterUYVYImage method is: |
206 | | % |
207 | | % RegisterUYVYImage(void) |
208 | | % |
209 | | */ |
210 | | ModuleExport void RegisterUYVYImage(void) |
211 | 2 | { |
212 | 2 | MagickInfo |
213 | 2 | *entry; |
214 | | |
215 | 2 | entry=SetMagickInfo("PAL"); |
216 | 2 | entry->decoder=(DecoderHandler) ReadUYVYImage; |
217 | 2 | entry->encoder=(EncoderHandler) WriteUYVYImage; |
218 | 2 | entry->adjoin=False; |
219 | 2 | entry->raw=True; |
220 | 2 | entry->description="16bit/pixel interleaved YUV"; |
221 | 2 | entry->module="UYVY"; |
222 | 2 | (void) RegisterMagickInfo(entry); |
223 | | |
224 | 2 | entry=SetMagickInfo("UYVY"); |
225 | 2 | entry->decoder=(DecoderHandler) ReadUYVYImage; |
226 | 2 | entry->encoder=(EncoderHandler) WriteUYVYImage; |
227 | 2 | entry->adjoin=False; |
228 | 2 | entry->raw=True; |
229 | 2 | entry->description="16bit/pixel interleaved YUV"; |
230 | 2 | entry->module="UYVY"; |
231 | 2 | (void) RegisterMagickInfo(entry); |
232 | 2 | } |
233 | | |
234 | | /* |
235 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
236 | | % % |
237 | | % % |
238 | | % % |
239 | | % U n r e g i s t e r U Y V Y I m a g e % |
240 | | % % |
241 | | % % |
242 | | % % |
243 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
244 | | % |
245 | | % Method UnregisterUYVYImage removes format registrations made by the |
246 | | % UYVY module from the list of supported formats. |
247 | | % |
248 | | % The format of the UnregisterUYVYImage method is: |
249 | | % |
250 | | % UnregisterUYVYImage(void) |
251 | | % |
252 | | */ |
253 | | ModuleExport void UnregisterUYVYImage(void) |
254 | 0 | { |
255 | 0 | (void) UnregisterMagickInfo("PAL"); |
256 | 0 | (void) UnregisterMagickInfo("UYVY"); |
257 | 0 | } |
258 | | |
259 | | /* |
260 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
261 | | % % |
262 | | % % |
263 | | % % |
264 | | % W r i t e U Y V Y I m a g e % |
265 | | % % |
266 | | % % |
267 | | % % |
268 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
269 | | % |
270 | | % Method WriteUYVYImage writes an image to a file in the digital UYVY |
271 | | % format. This format, used by AccomWSD, is not dramatically higher quality |
272 | | % than the 12bit/pixel YUV format, but has better locality. |
273 | | % |
274 | | % The format of the WriteUYVYImage method is: |
275 | | % |
276 | | % unsigned int WriteUYVYImage(const ImageInfo *image_info,Image *image) |
277 | | % |
278 | | % A description of each parameter follows. |
279 | | % |
280 | | % o status: Method WriteUYVYImage return True if the image is written. |
281 | | % False is returned is there is a memory shortage or if the image file |
282 | | % fails to write. |
283 | | % |
284 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
285 | | % |
286 | | % o image: A pointer to an Image structure. |
287 | | % Implicit assumption: number of columns is even. |
288 | | % |
289 | | */ |
290 | | static unsigned int WriteUYVYImage(const ImageInfo *image_info,Image *image) |
291 | 0 | { |
292 | 0 | DoublePixelPacket |
293 | 0 | pixel; |
294 | |
|
295 | 0 | long |
296 | 0 | y; |
297 | |
|
298 | 0 | register const PixelPacket |
299 | 0 | *p; |
300 | |
|
301 | 0 | register long |
302 | 0 | x; |
303 | |
|
304 | 0 | unsigned int |
305 | 0 | full, |
306 | 0 | status; |
307 | |
|
308 | 0 | ColorspaceType |
309 | 0 | original_colorspace; |
310 | | |
311 | | /* |
312 | | Open output image file. |
313 | | */ |
314 | 0 | assert(image_info != (const ImageInfo *) NULL); |
315 | 0 | assert(image_info->signature == MagickSignature); |
316 | 0 | assert(image != (Image *) NULL); |
317 | 0 | assert(image->signature == MagickSignature); |
318 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
319 | 0 | if (status == False) |
320 | 0 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
321 | | |
322 | | /* |
323 | | When subsampling, image width must be evenly divisible by two. |
324 | | */ |
325 | 0 | if (image->columns %2) |
326 | 0 | ThrowWriterException(CoderError,SubsamplingRequiresEvenWidth,image); |
327 | | |
328 | | /* |
329 | | Convert to YUV, at full resolution. |
330 | | */ |
331 | 0 | original_colorspace=image->colorspace; |
332 | 0 | if (TransformColorspace(image,YCbCrColorspace) == MagickFail) |
333 | 0 | ThrowWriterException(CoderError,UnableToTransformColorspace,image); |
334 | | /* |
335 | | Accumulate two pixels, then output. |
336 | | */ |
337 | 0 | full=False; |
338 | 0 | (void) memset(&pixel,0,sizeof(DoublePixelPacket)); |
339 | 0 | for (y=0; y < (long) image->rows; y++) |
340 | 0 | { |
341 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
342 | 0 | if (p == (const PixelPacket *) NULL) |
343 | 0 | break; |
344 | 0 | for (x=0; x < (long) image->columns; x++) |
345 | 0 | { |
346 | 0 | if (full) |
347 | 0 | { |
348 | 0 | pixel.green=(pixel.green+p->green)/2; |
349 | 0 | pixel.blue=(pixel.blue+p->blue)/2; |
350 | 0 | (void) WriteBlobByte(image,ScaleQuantumToChar(pixel.green)); |
351 | 0 | (void) WriteBlobByte(image,ScaleQuantumToChar(pixel.red)); |
352 | 0 | (void) WriteBlobByte(image,ScaleQuantumToChar(pixel.blue)); |
353 | 0 | (void) WriteBlobByte(image,ScaleQuantumToChar(p->red)); |
354 | 0 | } |
355 | 0 | pixel.red=p->red; |
356 | 0 | pixel.green=p->green; |
357 | 0 | pixel.blue=p->blue; |
358 | 0 | full=!full; |
359 | 0 | p++; |
360 | 0 | } |
361 | 0 | if (QuantumTick(y,image->rows)) |
362 | 0 | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
363 | 0 | SaveImageText,image->filename, |
364 | 0 | image->columns,image->rows)) |
365 | 0 | break; |
366 | 0 | } |
367 | | /* |
368 | | Restore colorspace |
369 | | */ |
370 | 0 | if (TransformColorspace(image,original_colorspace) == MagickFail) |
371 | 0 | ThrowWriterException(CoderError,UnableToTransformColorspace,image); |
372 | 0 | status &= CloseBlob(image); |
373 | 0 | return(status); |
374 | 0 | } |