| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514 |
- // Copyright (C) 2004-2024 Artifex Software, Inc.
- //
- // This file is part of MuPDF.
- //
- // MuPDF is free software: you can redistribute it and/or modify it under the
- // terms of the GNU Affero General Public License as published by the Free
- // Software Foundation, either version 3 of the License, or (at your option)
- // any later version.
- //
- // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
- // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
- // details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
- //
- // Alternative licensing terms are available from the licensor.
- // For commercial licensing, see <https://www.artifex.com/> or contact
- // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
- // CA 94129, USA, for further information.
- #include "mupdf/fitz.h"
- #include "image-imp.h"
- #include "pixmap-imp.h"
- #include <string.h>
- #include <limits.h>
- #undef BMP_DEBUG
- static const unsigned char web_palette[] = {
- 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x66, 0x00, 0x00, 0x99, 0x00, 0x00, 0xCC, 0x00, 0x00, 0xFF, 0x00, 0x00,
- 0x00, 0x00, 0x33, 0x33, 0x00, 0x33, 0x66, 0x00, 0x33, 0x99, 0x00, 0x33, 0xCC, 0x00, 0x33, 0xFF, 0x00, 0x33,
- 0x00, 0x00, 0x66, 0x33, 0x00, 0x66, 0x66, 0x00, 0x66, 0x99, 0x00, 0x66, 0xCC, 0x00, 0x66, 0xFF, 0x00, 0x66,
- 0x00, 0x00, 0x99, 0x33, 0x00, 0x99, 0x66, 0x00, 0x99, 0x99, 0x00, 0x99, 0xCC, 0x00, 0x99, 0xFF, 0x00, 0x99,
- 0x00, 0x00, 0xCC, 0x33, 0x00, 0xCC, 0x66, 0x00, 0xCC, 0x99, 0x00, 0xCC, 0xCC, 0x00, 0xCC, 0xFF, 0x00, 0xCC,
- 0x00, 0x00, 0xFF, 0x33, 0x00, 0xFF, 0x66, 0x00, 0xFF, 0x99, 0x00, 0xFF, 0xCC, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
- 0x00, 0x33, 0x00, 0x33, 0x33, 0x00, 0x66, 0x33, 0x00, 0x99, 0x33, 0x00, 0xCC, 0x33, 0x00, 0xFF, 0x33, 0x00,
- 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF, 0x33, 0x33,
- 0x00, 0x33, 0x66, 0x33, 0x33, 0x66, 0x66, 0x33, 0x66, 0x99, 0x33, 0x66, 0xCC, 0x33, 0x66, 0xFF, 0x33, 0x66,
- 0x00, 0x33, 0x99, 0x33, 0x33, 0x99, 0x66, 0x33, 0x99, 0x99, 0x33, 0x99, 0xCC, 0x33, 0x99, 0xFF, 0x33, 0x99,
- 0x00, 0x33, 0xCC, 0x33, 0x33, 0xCC, 0x66, 0x33, 0xCC, 0x99, 0x33, 0xCC, 0xCC, 0x33, 0xCC, 0xFF, 0x33, 0xCC,
- 0x00, 0x33, 0xFF, 0x33, 0x33, 0xFF, 0x66, 0x33, 0xFF, 0x99, 0x33, 0xFF, 0xCC, 0x33, 0xFF, 0xFF, 0x33, 0xFF,
- 0x00, 0x66, 0x00, 0x33, 0x66, 0x00, 0x66, 0x66, 0x00, 0x99, 0x66, 0x00, 0xCC, 0x66, 0x00, 0xFF, 0x66, 0x00,
- 0x00, 0x66, 0x33, 0x33, 0x66, 0x33, 0x66, 0x66, 0x33, 0x99, 0x66, 0x33, 0xCC, 0x66, 0x33, 0xFF, 0x66, 0x33,
- 0x00, 0x66, 0x66, 0x33, 0x66, 0x66, 0x66, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF, 0x66, 0x66,
- 0x00, 0x66, 0x99, 0x33, 0x66, 0x99, 0x66, 0x66, 0x99, 0x99, 0x66, 0x99, 0xCC, 0x66, 0x99, 0xFF, 0x66, 0x99,
- 0x00, 0x66, 0xCC, 0x33, 0x66, 0xCC, 0x66, 0x66, 0xCC, 0x99, 0x66, 0xCC, 0xCC, 0x66, 0xCC, 0xFF, 0x66, 0xCC,
- 0x00, 0x66, 0xFF, 0x33, 0x66, 0xFF, 0x66, 0x66, 0xFF, 0x99, 0x66, 0xFF, 0xCC, 0x66, 0xFF, 0xFF, 0x66, 0xFF,
- 0x00, 0x99, 0x00, 0x33, 0x99, 0x00, 0x66, 0x99, 0x00, 0x99, 0x99, 0x00, 0xCC, 0x99, 0x00, 0xFF, 0x99, 0x00,
- 0x00, 0x99, 0x33, 0x33, 0x99, 0x33, 0x66, 0x99, 0x33, 0x99, 0x99, 0x33, 0xCC, 0x99, 0x33, 0xFF, 0x99, 0x33,
- 0x00, 0x99, 0x66, 0x33, 0x99, 0x66, 0x66, 0x99, 0x66, 0x99, 0x99, 0x66, 0xCC, 0x99, 0x66, 0xFF, 0x99, 0x66,
- 0x00, 0x99, 0x99, 0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0x99, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF, 0x99, 0x99,
- 0x00, 0x99, 0xCC, 0x33, 0x99, 0xCC, 0x66, 0x99, 0xCC, 0x99, 0x99, 0xCC, 0xCC, 0x99, 0xCC, 0xFF, 0x99, 0xCC,
- 0x00, 0x99, 0xFF, 0x33, 0x99, 0xFF, 0x66, 0x99, 0xFF, 0x99, 0x99, 0xFF, 0xCC, 0x99, 0xFF, 0xFF, 0x99, 0xFF,
- 0x00, 0xCC, 0x00, 0x33, 0xCC, 0x00, 0x66, 0xCC, 0x00, 0x99, 0xCC, 0x00, 0xCC, 0xCC, 0x00, 0xFF, 0xCC, 0x00,
- 0x00, 0xCC, 0x33, 0x33, 0xCC, 0x33, 0x66, 0xCC, 0x33, 0x99, 0xCC, 0x33, 0xCC, 0xCC, 0x33, 0xFF, 0xCC, 0x33,
- 0x00, 0xCC, 0x66, 0x33, 0xCC, 0x66, 0x66, 0xCC, 0x66, 0x99, 0xCC, 0x66, 0xCC, 0xCC, 0x66, 0xFF, 0xCC, 0x66,
- 0x00, 0xCC, 0x99, 0x33, 0xCC, 0x99, 0x66, 0xCC, 0x99, 0x99, 0xCC, 0x99, 0xCC, 0xCC, 0x99, 0xFF, 0xCC, 0x99,
- 0x00, 0xCC, 0xCC, 0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFF, 0xCC, 0xCC,
- 0x00, 0xCC, 0xFF, 0x33, 0xCC, 0xFF, 0x66, 0xCC, 0xFF, 0x99, 0xCC, 0xFF, 0xCC, 0xCC, 0xFF, 0xFF, 0xCC, 0xFF,
- 0x00, 0xFF, 0x00, 0x33, 0xFF, 0x00, 0x66, 0xFF, 0x00, 0x99, 0xFF, 0x00, 0xCC, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0xFF, 0x33, 0x33, 0xFF, 0x33, 0x66, 0xFF, 0x33, 0x99, 0xFF, 0x33, 0xCC, 0xFF, 0x33, 0xFF, 0xFF, 0x33,
- 0x00, 0xFF, 0x66, 0x33, 0xFF, 0x66, 0x66, 0xFF, 0x66, 0x99, 0xFF, 0x66, 0xCC, 0xFF, 0x66, 0xFF, 0xFF, 0x66,
- 0x00, 0xFF, 0x99, 0x33, 0xFF, 0x99, 0x66, 0xFF, 0x99, 0x99, 0xFF, 0x99, 0xCC, 0xFF, 0x99, 0xFF, 0xFF, 0x99,
- 0x00, 0xFF, 0xCC, 0x33, 0xFF, 0xCC, 0x66, 0xFF, 0xCC, 0x99, 0xFF, 0xCC, 0xCC, 0xFF, 0xCC, 0xFF, 0xFF, 0xCC,
- 0x00, 0xFF, 0xFF, 0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- };
- static const unsigned char vga_palette[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0x00, 0xAA, 0xAA,
- 0xAA, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0xAA, 0x55, 0x00, 0xAA, 0xAA, 0xAA,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0x55, 0xFF, 0xFF,
- 0xFF, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF,
- };
- static const unsigned char gray_palette[] = {
- 0x00, 0x00, 0x00, 0x54, 0x54, 0x54,
- 0xA8, 0xA8, 0xA8, 0xFF, 0xFF, 0xFF,
- };
- static const unsigned char bw_palette[] = {
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
- };
- enum {
- BI_NONE = 0,
- BI_RLE8 = 1,
- BI_RLE4 = 2,
- BI_BITFIELDS = 3,
- BI_HUFFMAN1D = 3,
- BI_JPEG = 4,
- BI_RLE24 = 4,
- BI_PNG = 5,
- BI_ALPHABITS = 6,
- };
- struct info
- {
- char type[2];
- uint32_t version;
- uint32_t bitmapoffset;
- uint32_t width, height;
- uint16_t bitcount;
- uint32_t compression;
- uint32_t bitmapsize;
- uint32_t xres, yres;
- uint32_t colors;
- uint32_t rmask, gmask, bmask, amask;
- uint8_t palette[256 * 3];
- uint32_t colorspacetype;
- uint32_t endpoints[3 * 3];
- uint32_t gamma[3];
- uint32_t intent;
- uint32_t profileoffset;
- uint32_t profilesize;
- int topdown;
- unsigned int rshift, gshift, bshift, ashift;
- unsigned int rbits, gbits, bbits, abits;
- unsigned char *samples;
- fz_colorspace *cs;
- };
- #define read8(p) ((p)[0])
- #define read16(p) (((p)[1] << 8) | (p)[0])
- #define read32(p) (((p)[3] << 24) | ((p)[2] << 16) | ((p)[1] << 8) | (p)[0])
- #define DPM_TO_DPI(dpm) ((dpm) * 25.4f / 1000.0f)
- #define is_bitmap_array(p) ((p)[0] == 'B' && (p)[1] == 'A')
- #define is_bitmap(p) ((p)[0] == 'B' && (p)[1] == 'M')
- #define is_os2_bmp(info) ((info)->version == 12 || (info)->version == 16 || (info)->version == 64)
- #define is_win_bmp(info) ((info)->version == 12 || (info)->version == 40 || (info)->version == 52 || (info)->version == 56 || (info)->version == 108 || (info)->version == 124)
- #define is_valid_win_compression(info) (is_win_bmp(info) && ((info)->compression == BI_NONE || (info)->compression == BI_RLE8 || (info)->compression == BI_RLE4 || (info)->compression == BI_BITFIELDS || (info)->compression == BI_JPEG || (info)->compression == BI_PNG || (info)->compression == BI_ALPHABITS || (info)->compression == BI_RLE24))
- #define is_valid_os2_compression(info) (is_os2_bmp(info) && ((info)->compression == BI_NONE || (info)->compression == BI_RLE8 || (info)->compression == BI_RLE4 || (info)->compression == BI_HUFFMAN1D || (info)->compression == BI_RLE24))
- #define is_valid_compression(info) (is_valid_win_compression(info) || is_valid_os2_compression(info))
- #define is_valid_rgb_bitcount(info) ((info)->compression == BI_NONE && ((info)->bitcount == 1 || (info)->bitcount == 2 || (info)->bitcount == 4 || (info)->bitcount == 8 || (info)->bitcount == 16 || (info)->bitcount == 24 || (info)->bitcount == 32 || (info)->bitcount == 64))
- #define is_valid_rle8_bitcount(info) ((info)->compression == BI_RLE8 && (info)->bitcount == 8)
- #define is_valid_rle4_bitcount(info) ((info)->compression == BI_RLE4 && (info)->bitcount == 4)
- #define is_valid_bitfields_bitcount(info) (is_win_bmp(info) && (info)->compression == BI_BITFIELDS && ((info)->bitcount == 16 || (info)->bitcount == 32))
- #define is_valid_jpeg_bitcount(info) (is_win_bmp(info) && (info)->compression == BI_JPEG && (info)->bitcount == 0)
- #define is_valid_png_bitcount(info) (is_win_bmp(info) && (info)->compression == BI_PNG && (info)->bitcount == 0)
- #define is_valid_alphabits_bitcount(info) (is_win_bmp(info) && (info)->compression == BI_ALPHABITS && ((info)->bitcount == 16 || (info)->bitcount == 32))
- #define is_valid_rle24_bitcount(info) (is_os2_bmp(info) && (info)->compression == BI_RLE24 && (info)->bitcount == 24)
- #define is_valid_huffman1d_bitcount(info) (is_os2_bmp(info) && (info)->compression == BI_HUFFMAN1D && (info)->bitcount == 1)
- #define is_valid_bitcount(info) (is_valid_rgb_bitcount(info) || is_valid_rle8_bitcount(info) || is_valid_rle4_bitcount(info) || is_valid_bitfields_bitcount(info) || is_valid_jpeg_bitcount(info) || is_valid_png_bitcount(info) || is_valid_alphabits_bitcount(info) || is_valid_rle24_bitcount(info) || is_valid_huffman1d_bitcount(info))
- #define has_palette(info) ((info)->bitcount == 1 || (info)->bitcount == 2 || (info)->bitcount == 4 || (info)->bitcount == 8)
- #define has_color_masks(info) (((info)->bitcount == 16 || (info)->bitcount == 32) && (info)->version == 40 && ((info)->compression == BI_BITFIELDS || (info)->compression == BI_ALPHABITS))
- #define has_color_profile(info) ((info)->version == 108 || (info)->version == 124)
- #define palette_entry_size(info) ((info)->version == 12 ? 3 : 4)
- static const unsigned char *
- bmp_read_file_header(fz_context *ctx, struct info *info, const unsigned char *begin, const unsigned char *end, const unsigned char *p)
- {
- if (end - p < 14)
- fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in file header in bmp image");
- if (!is_bitmap(p))
- fz_throw(ctx, FZ_ERROR_FORMAT, "invalid signature %02x%02x in bmp image", p[0], p[1]);
- info->type[0] = read8(p + 0);
- info->type[1] = read8(p + 1);
- /* read32(p+2) == file or header size */
- /* read16(p+6) == hotspot x for icons/cursors */
- /* read16(p+8) == hotspot y for icons/cursors */
- info->bitmapoffset = read32(p + 10);
- return p + 14;
- }
- static unsigned char *
- bmp_decompress_huffman1d(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char **end)
- {
- fz_stream *encstm, *decstm;
- fz_buffer *buf;
- unsigned char *decoded;
- size_t size;
- encstm = fz_open_memory(ctx, p, *end - p);
- fz_var(decstm);
- fz_var(buf);
- fz_try(ctx)
- {
- decstm = fz_open_faxd(ctx, encstm,
- 0, /* 1 dimensional encoding */
- 0, /* end of line not required */
- 0, /* encoded byte align */
- info->width, info->height,
- 0, /* end of block expected */
- 1 /* black is 1 */
- );
- buf = fz_read_all(ctx, decstm, 1024);
- size = fz_buffer_extract(ctx, buf, &decoded);
- *end = decoded + size;
- }
- fz_always(ctx)
- {
- fz_drop_buffer(ctx, buf);
- fz_drop_stream(ctx, decstm);
- fz_drop_stream(ctx, encstm);
- }
- fz_catch(ctx)
- fz_rethrow(ctx);
- return decoded;
- }
- static unsigned char *
- bmp_decompress_rle24(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char **end)
- {
- const unsigned char *sp;
- unsigned char *dp, *ep, *decompressed;
- uint32_t width = info->width;
- uint32_t height = info->height;
- uint32_t stride;
- uint32_t x, y;
- int i;
- stride = (width*3 + 3) / 4 * 4;
- sp = p;
- dp = decompressed = fz_calloc(ctx, height, stride);
- ep = dp + height * stride;
- x = 0;
- y = 0;
- while (sp + 2 <= *end)
- {
- if (sp[0] == 0 && sp[1] == 0)
- { /* end of line */
- sp += 2;
- x = 0;
- y++;
- }
- else if (sp[0] == 0 && sp[1] == 1)
- { /* end of bitmap */
- sp += 2;
- break;
- }
- else if (sp[0] == 0 && sp[1] == 2)
- { /* delta */
- sp += 2;
- x += sp < *end ? *sp++ : 0;
- y += sp < *end ? *sp++ : 0;
- }
- else if (sp[0] == 0 && sp[1] >= 3)
- { /* absolute */
- int dn, sn, pad;
- dn = sp[1];
- sn = (dn * 3 + 1) / 2 * 2;
- pad = sn & 1;
- sp += 2;
- if (sn > *end - sp)
- {
- fz_warn(ctx, "premature end of pixel data in absolute code in bmp image");
- sn = ((*end - sp) / 3) * 3;
- pad = (*end - sp) % 3;
- dn = sn / 3;
- }
- else if (sn + pad > *end - sp)
- {
- fz_warn(ctx, "premature end of padding in absolute code in bmp image");
- pad = 0;
- }
- for (i = 0; i < dn; i++)
- {
- uint32_t actualx = x;
- uint32_t actualy = y;
- if (actualx >= width || actualy >= height)
- {
- actualx = x % width;
- actualy = y + x / width;
- }
- if (actualx < width && actualy < height)
- {
- dp = decompressed + actualy * stride + actualx * 3;
- *dp++ = sp[i * 3 + 0];
- *dp++ = sp[i * 3 + 1];
- *dp++ = sp[i * 3 + 2];
- }
- x++;
- }
- sp += sn + pad;
- }
- else
- { /* encoded */
- int dn, sn;
- dn = sp[0];
- sn = 3;
- sp++;
- if (sn > *end - sp)
- {
- fz_warn(ctx, "premature end of pixel data in encoded code in bmp image");
- sn = 0;
- dn = 0;
- }
- for (i = 0; i < dn; i++)
- {
- uint32_t actualx = x;
- uint32_t actualy = y;
- if (actualx >= width || actualy >= height)
- {
- actualx = x % width;
- actualy = y + x / width;
- }
- if (actualx < width && actualy < height)
- {
- dp = decompressed + actualy * stride + actualx * 3;
- *dp++ = sp[0];
- *dp++ = sp[1];
- *dp++ = sp[2];
- }
- x++;
- }
- sp += sn;
- }
- }
- info->compression = BI_NONE;
- info->bitcount = 24;
- *end = ep;
- return decompressed;
- }
- static unsigned char *
- bmp_decompress_rle8(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char **end)
- {
- const unsigned char *sp;
- unsigned char *dp, *ep, *decompressed;
- uint32_t width = info->width;
- uint32_t height = info->height;
- uint32_t stride;
- uint32_t x, y;
- int i;
- stride = (width + 3) / 4 * 4;
- sp = p;
- dp = decompressed = fz_calloc(ctx, height, stride);
- ep = dp + height * stride;
- x = 0;
- y = 0;
- while (sp + 2 <= *end)
- {
- if (sp[0] == 0 && sp[1] == 0)
- { /* end of line */
- sp += 2;
- x = 0;
- y++;
- }
- else if (sp[0] == 0 && sp[1] == 1)
- { /* end of bitmap */
- sp += 2;
- break;
- }
- else if (sp[0] == 0 && sp[1] == 2)
- { /* delta */
- sp +=2;
- x += sp < *end ? *sp++ : 0;
- y += sp < *end ? *sp++ : 0;
- }
- else if (sp[0] == 0 && sp[1] >= 3)
- { /* absolute */
- int dn, sn, pad;
- dn = sp[1];
- sn = dn;
- pad = sn & 1;
- sp += 2;
- if (sn > *end - sp)
- {
- fz_warn(ctx, "premature end of pixel data in absolute code in bmp image");
- sn = *end - sp;
- pad = 0;
- dn = sn;
- }
- else if (sn + pad > *end - sp)
- {
- fz_warn(ctx, "premature end of padding in absolute code in bmp image");
- pad = 0;
- }
- for (i = 0; i < dn; i++)
- {
- uint32_t actualx = x;
- uint32_t actualy = y;
- if (actualx >= width || actualy >= height)
- {
- actualx = x % width;
- actualy = y + x / width;
- }
- if (actualx < width && actualy < height)
- {
- dp = decompressed + actualy * stride + actualx;
- *dp++ = sp[i];
- }
- x++;
- }
- sp += sn + pad;
- }
- else
- { /* encoded */
- int dn, sn;
- dn = sp[0];
- sn = 1;
- sp++;
- for (i = 0; i < dn; i++)
- {
- uint32_t actualx = x;
- uint32_t actualy = y;
- if (actualx >= width || actualy >= height)
- {
- actualx = x % width;
- actualy = y + x / width;
- }
- if (actualx < width && actualy < height)
- {
- dp = decompressed + actualy * stride + actualx;
- *dp++ = sp[0];
- }
- x++;
- }
- sp += sn;
- }
- }
- info->compression = BI_NONE;
- info->bitcount = 8;
- *end = ep;
- return decompressed;
- }
- static unsigned char *
- bmp_decompress_rle4(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char **end)
- {
- const unsigned char *sp;
- unsigned char *dp, *ep, *decompressed;
- uint32_t width = info->width;
- uint32_t height = info->height;
- uint32_t stride;
- uint32_t x, y;
- int i;
- stride = ((width + 1) / 2 + 3) / 4 * 4;
- sp = p;
- dp = decompressed = fz_calloc(ctx, height, stride);
- ep = dp + height * stride;
- x = 0;
- y = 0;
- while (sp + 2 <= *end)
- {
- if (sp[0] == 0 && sp[1] == 0)
- { /* end of line */
- sp += 2;
- x = 0;
- y++;
- }
- else if (sp[0] == 0 && sp[1] == 1)
- { /* end of bitmap */
- sp += 2;
- break;
- }
- else if (sp[0] == 0 && sp[1] == 2)
- { /* delta */
- sp += 2;
- x += sp < *end ? *sp++ : 0;
- y += sp < *end ? *sp++ : 0;
- }
- else if (sp[0] == 0 && sp[1] >= 3)
- { /* absolute */
- int dn, sn, pad;
- dn = sp[1];
- sn = (dn + 1) / 2;
- pad = sn & 1;
- sp += 2;
- if (sn > *end - sp)
- {
- fz_warn(ctx, "premature end of pixel data in absolute code in bmp image");
- sn = *end - sp;
- pad = 0;
- dn = sn * 2;
- }
- else if (sn + pad > *end - sp)
- {
- fz_warn(ctx, "premature end of padding in absolute code in bmp image");
- pad = 0;
- }
- for (i = 0; i < dn; i++)
- {
- uint32_t actualx = x;
- uint32_t actualy = y;
- if (actualx >= width || actualy >= height)
- {
- actualx = x % width;
- actualy = y + x / width;
- }
- if (actualx < width && actualy < height)
- {
- int val = i & 1 ? (sp[i >> 1]) & 0xF : (sp[i >> 1] >> 4) & 0xF;
- dp = decompressed + actualy * stride + actualx / 2;
- if (x & 1)
- *dp++ |= val;
- else
- *dp |= val << 4;
- }
- x++;
- }
- sp += sn + pad;
- }
- else
- { /* encoded */
- int dn, sn;
- dn = sp[0];
- sn = 1;
- sp++;
- for (i = 0; i < dn; i++)
- {
- uint32_t actualx = x;
- uint32_t actualy = y;
- if (actualx >= width || actualy >= height)
- {
- actualx = x % width;
- actualy = y + x / width;
- }
- if (actualx < width && actualy < height)
- {
- int val = i & 1 ? (sp[0] & 0xf) : (sp[0] >> 4) & 0xf;
- dp = decompressed + actualy * stride + actualx / 2;
- if (x & 1)
- *dp++ |= val;
- else
- *dp |= val << 4;
- }
- x++;
- }
- sp += sn;
- }
- }
- info->compression = BI_NONE;
- info->bitcount = 4;
- *end = ep;
- return decompressed;
- }
- static fz_pixmap *
- bmp_read_bitmap(fz_context *ctx, struct info *info, const unsigned char *begin, const unsigned char *end, const unsigned char *p)
- {
- const unsigned int mults[] = { 0, 8191, 2730, 1170, 546, 264, 130, 64 };
- fz_pixmap *pix;
- const unsigned char *ssp;
- unsigned char *ddp;
- unsigned char *decompressed = NULL;
- uint32_t bitcount;
- uint32_t width;
- int32_t height;
- uint32_t sstride;
- int32_t dstride;
- unsigned int rmult, gmult, bmult, amult;
- unsigned int rtrunc, gtrunc, btrunc, atrunc;
- uint32_t x;
- int32_t y;
- assert(info->width > 0 && info->width <= SHRT_MAX);
- assert(info->height > 0 && info->height <= SHRT_MAX);
- if (info->compression == BI_NONE)
- ssp = p;
- else if (info->compression == BI_RLE4)
- ssp = decompressed = bmp_decompress_rle4(ctx, info, p, &end);
- else if (info->compression == BI_RLE8)
- ssp = decompressed = bmp_decompress_rle8(ctx, info, p, &end);
- else if (is_win_bmp(info) && (info->compression == BI_BITFIELDS || info->compression == BI_ALPHABITS))
- ssp = p;
- else if (is_os2_bmp(info) && info->compression == BI_RLE24)
- ssp = decompressed = bmp_decompress_rle24(ctx, info, p, &end);
- else if (is_os2_bmp(info) && info->compression == BI_HUFFMAN1D)
- ssp = decompressed = bmp_decompress_huffman1d(ctx, info, p, &end);
- else
- fz_throw(ctx, FZ_ERROR_FORMAT, "unhandled compression (%u) in bmp image", info->compression);
- bitcount = info->bitcount;
- width = info->width;
- height = info->height;
- sstride = ((width * bitcount + 31) / 32) * 4;
- if (ssp + sstride * height > end)
- {
- int32_t h = (end - ssp) / sstride;
- if (h == 0 || h > SHRT_MAX)
- {
- fz_free(ctx, decompressed);
- fz_throw(ctx, FZ_ERROR_LIMIT, "image dimensions out of range in bmp image");
- }
- }
- fz_try(ctx)
- {
- pix = fz_new_pixmap(ctx, info->cs, width, height, NULL, 1);
- fz_set_pixmap_resolution(ctx, pix, info->xres, info->yres);
- fz_clear_pixmap(ctx, pix);
- }
- fz_catch(ctx)
- {
- fz_free(ctx, decompressed);
- fz_rethrow(ctx);
- }
- ddp = pix->samples;
- dstride = pix->stride;
- if (!info->topdown)
- {
- ddp = pix->samples + ((size_t) (height - 1)) * ((size_t) dstride);
- dstride = -dstride;
- }
- if (ssp + sstride * height > end)
- {
- fz_warn(ctx, "premature end in bitmap data in bmp image");
- height = (end - ssp) / sstride;
- }
- /* These are only used for 16- and 32-bit components
- 1-bit (1 * 8191) / 32
- 2-bit (3 * 2730) / 32
- 3-bit (7 * 1170) / 32
- 4-bit (15 * 546) / 32
- 5-bit (31 * 264) / 32
- 6-bit (63 * 130) / 32
- 7-bit (127 * 64) / 32
- */
- rmult = info->rbits < 8 ? mults[info->rbits] : 1;
- gmult = info->gbits < 8 ? mults[info->gbits] : 1;
- bmult = info->bbits < 8 ? mults[info->bbits] : 1;
- amult = info->abits < 8 ? mults[info->abits] : 1;
- rtrunc = info->rbits < 8 ? 5 : (info->rbits - 8);
- gtrunc = info->gbits < 8 ? 5 : (info->gbits - 8);
- btrunc = info->bbits < 8 ? 5 : (info->bbits - 8);
- atrunc = info->abits < 8 ? 5 : (info->abits - 8);
- #ifdef BMP_DEBUG
- fz_warn(ctx, "rbits = %2d mult = %2d trunc = %2d", info->rbits, rmult, rtrunc);
- fz_warn(ctx, "gbits = %2d mult = %2d trunc = %2d", info->gbits, gmult, gtrunc);
- fz_warn(ctx, "bbits = %2d mult = %2d trunc = %2d", info->bbits, bmult, btrunc);
- fz_warn(ctx, "abits = %2d mult = %2d trunc = %2d", info->abits, amult, atrunc);
- #endif
- for (y = 0; y < height; y++)
- {
- const unsigned char *sp = ssp + ((size_t) y) * ((size_t) sstride);
- unsigned char *dp = ddp + ((size_t) y) * ((size_t) dstride);
- switch (bitcount)
- {
- case 64:
- for (x = 0; x < width; x++)
- {
- uint32_t a = (((uint16_t)sp[7]) << 8) | (((uint16_t)sp[6]) << 0);
- uint32_t r = (((uint16_t)sp[5]) << 8) | (((uint16_t)sp[4]) << 0);
- uint32_t g = (((uint16_t)sp[3]) << 8) | (((uint16_t)sp[2]) << 0);
- uint32_t b = (((uint16_t)sp[1]) << 8) | (((uint16_t)sp[0]) << 0);
- r = (r * 255 + 4096) >> 13;
- g = (g * 255 + 4096) >> 13;
- b = (b * 255 + 4096) >> 13;
- a = (a * 255 + 4096) >> 13;
- *dp++ = r;
- *dp++ = g;
- *dp++ = b;
- *dp++ = a;
- sp += 8;
- }
- break;
- case 32:
- for (x = 0; x < width; x++)
- {
- uint32_t sample =
- (((uint32_t) sp[3]) << 24) |
- (((uint32_t) sp[2]) << 16) |
- (((uint32_t) sp[1]) << 8) |
- (((uint32_t) sp[0]) << 0);
- uint32_t r = (sample & info->rmask) >> info->rshift;
- uint32_t g = (sample & info->gmask) >> info->gshift;
- uint32_t b = (sample & info->bmask) >> info->bshift;
- uint32_t a = info->abits == 0 ? 255 : (sample & info->amask) >> info->ashift;
- *dp++ = (r * rmult) >> rtrunc;
- *dp++ = (g * gmult) >> gtrunc;
- *dp++ = (b * bmult) >> btrunc;
- *dp++ = info->abits == 0 ? a : (a * amult) >> atrunc;
- sp += 4;
- }
- break;
- case 24:
- for (x = 0; x < width; x++)
- {
- *dp++ = sp[2];
- *dp++ = sp[1];
- *dp++ = sp[0];
- *dp++ = 255;
- sp += 3;
- }
- break;
- case 16:
- for (x = 0; x < width; x++)
- {
- uint16_t sample =
- (((uint16_t)sp[1]) << 8) |
- (((uint16_t)sp[0]) << 0);
- uint16_t r = (sample & info->rmask) >> info->rshift;
- uint16_t g = (sample & info->gmask) >> info->gshift;
- uint16_t b = (sample & info->bmask) >> info->bshift;
- uint16_t a = (sample & info->amask) >> info->ashift;
- *dp++ = (r * rmult) >> rtrunc;
- *dp++ = (g * gmult) >> gtrunc;
- *dp++ = (b * bmult) >> btrunc;
- *dp++ = info->abits == 0 ? 255 : (a * amult) >> atrunc;
- sp += 2;
- }
- break;
- case 8:
- for (x = 0; x < width; x++)
- {
- *dp++ = info->palette[3 * sp[0] + 0];
- *dp++ = info->palette[3 * sp[0] + 1];
- *dp++ = info->palette[3 * sp[0] + 2];
- *dp++ = 255;
- sp++;
- }
- break;
- case 4:
- for (x = 0; x < width; x++)
- {
- int idx;
- switch (x & 1)
- {
- case 0: idx = (sp[0] >> 4) & 0x0f; break;
- case 1: idx = (sp[0] >> 0) & 0x0f; sp++; break;
- }
- *dp++ = info->palette[3 * idx + 0];
- *dp++ = info->palette[3 * idx + 1];
- *dp++ = info->palette[3 * idx + 2];
- *dp++ = 255;
- }
- break;
- case 2:
- for (x = 0; x < width; x++)
- {
- int idx;
- switch (x & 3)
- {
- case 0: idx = (sp[0] >> 6) & 0x03; break;
- case 1: idx = (sp[0] >> 4) & 0x03; break;
- case 2: idx = (sp[0] >> 2) & 0x03; break;
- case 3: idx = (sp[0] >> 0) & 0x03; sp++; break;
- }
- *dp++ = info->palette[3 * idx + 0];
- *dp++ = info->palette[3 * idx + 1];
- *dp++ = info->palette[3 * idx + 2];
- *dp++ = 255;
- }
- break;
- case 1:
- for (x = 0; x < width; x++)
- {
- int idx;
- switch (x & 7)
- {
- case 0: idx = (sp[0] >> 7) & 0x01; break;
- case 1: idx = (sp[0] >> 6) & 0x01; break;
- case 2: idx = (sp[0] >> 5) & 0x01; break;
- case 3: idx = (sp[0] >> 4) & 0x01; break;
- case 4: idx = (sp[0] >> 3) & 0x01; break;
- case 5: idx = (sp[0] >> 2) & 0x01; break;
- case 6: idx = (sp[0] >> 1) & 0x01; break;
- case 7: idx = (sp[0] >> 0) & 0x01; sp++; break;
- }
- *dp++ = info->palette[3 * idx + 0];
- *dp++ = info->palette[3 * idx + 1];
- *dp++ = info->palette[3 * idx + 2];
- *dp++ = 255;
- }
- break;
- }
- }
- fz_free(ctx, decompressed);
- fz_premultiply_pixmap(ctx, pix);
- return pix;
- }
- static fz_colorspace *
- bmp_read_color_profile(fz_context *ctx, struct info *info, const unsigned char *begin, const unsigned char *end)
- {
- if (info->colorspacetype == 0)
- {
- float matrix[9] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
- float wp[3] = { 0.95047f, 1.0f, 1.08883f }; /* D65 white point */
- float bp[3] = { 0, 0, 0 };
- float gamma[3] = { 1, 1, 1 };
- int i;
- for (i = 0; i < 3; i++)
- gamma[i] = (float) info->gamma[i] / (float) (1 << 16);
- for (i = 0; i < 9; i++)
- matrix[i] = (float) info->endpoints[i] / (float) (1 << 30);
- #ifdef BMP_DEBUG
- fz_warn(ctx, "wp = %.6f %.6f %.6f", wp[0], wp[1], wp[2]);
- fz_warn(ctx, "bp = %.6f %.6f %.6f", bp[0], bp[1], bp[2]);
- fz_warn(ctx, "endpoints = %.6f %.6f %.6f", matrix[0], matrix[1], matrix[2]);
- fz_warn(ctx, "endpoints = %.6f %.6f %.6f", matrix[3], matrix[4], matrix[5]);
- fz_warn(ctx, "endpoints = %.6f %.6f %.6f", matrix[6], matrix[7], matrix[8]);
- fz_warn(ctx, "gamma = %.6f %.6f %.6f", gamma[0], gamma[1], gamma[2]);
- #endif
- return fz_new_cal_rgb_colorspace(ctx, wp, bp, gamma, matrix);
- }
- else if (info->colorspacetype == 0x4c494e4b)
- {
- fz_warn(ctx, "ignoring linked color profile in bmp image");
- return NULL;
- }
- else if (info->colorspacetype == 0x57696e20)
- {
- fz_warn(ctx, "ignoring windows color profile in bmp image");
- return NULL;
- }
- else if (info->colorspacetype == 0x4d424544)
- {
- fz_buffer *profile;
- fz_colorspace *cs;
- if ((uint32_t)(end - begin) <= info->profileoffset)
- {
- fz_warn(ctx, "ignoring color profile located outside bmp image");
- return NULL;
- }
- if ((uint32_t)(end - begin) - info->profileoffset < info->profilesize)
- {
- fz_warn(ctx, "ignoring truncated color profile in bmp image");
- return NULL;
- }
- if (info->profilesize == 0)
- {
- fz_warn(ctx, "ignoring color profile without data in bmp image");
- return NULL;
- }
- profile = fz_new_buffer_from_copied_data(ctx, begin + info->profileoffset, info->profilesize);
- fz_try(ctx)
- cs = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_RGB, 0, "BMPRGB", profile);
- fz_always(ctx)
- fz_drop_buffer(ctx, profile);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return cs;
- }
- else if (info->colorspacetype == 0x73524742)
- {
- return fz_keep_colorspace(ctx, fz_device_rgb(ctx));
- }
- fz_warn(ctx, "ignoring color profile with unknown type in bmp image");
- return NULL;
- }
- static void
- compute_mask_info(unsigned int mask, unsigned int *shift, unsigned int *bits)
- {
- *bits = 0;
- *shift = 0;
- while (mask && (mask & 1) == 0) {
- *shift += 1;
- mask >>= 1;
- }
- while (mask && (mask & 1) == 1) {
- *bits += 1;
- mask >>= 1;
- }
- }
- static const unsigned char *
- bmp_read_color_masks(fz_context *ctx, struct info *info, const unsigned char *begin, const unsigned char *end, const unsigned char *p)
- {
- int size = 0;
- if (info->compression == BI_BITFIELDS)
- {
- size = 12;
- if (end - p < 12)
- fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in mask header in bmp image");
- info->rmask = read32(p + 0);
- info->gmask = read32(p + 4);
- info->bmask = read32(p + 8);
- }
- else if (info->compression == BI_ALPHABITS)
- {
- size = 16;
- if (end - p < 16)
- fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in mask header in bmp image");
- info->rmask = read32(p + 0);
- info->gmask = read32(p + 4);
- info->bmask = read32(p + 8);
- info->amask = read32(p + 12);
- }
- return p + size;
- }
- static int
- bmp_palette_is_gray(fz_context *ctx, struct info *info, int readcolors)
- {
- int i;
- for (i = 0; i < readcolors; i++)
- {
- int rgdiff = fz_absi(info->palette[3 * i + 0] - info->palette[3 * i + 1]);
- int gbdiff = fz_absi(info->palette[3 * i + 1] - info->palette[3 * i + 2]);
- int rbdiff = fz_absi(info->palette[3 * i + 0] - info->palette[3 * i + 2]);
- if (rgdiff > 2 || gbdiff > 2 || rbdiff > 2)
- return 0;
- }
- return 1;
- }
- static void
- bmp_load_default_palette(fz_context *ctx, struct info *info, int readcolors)
- {
- int i;
- fz_warn(ctx, "color table too short; loading default palette");
- if (info->bitcount == 8)
- {
- if (!bmp_palette_is_gray(ctx, info, readcolors))
- memcpy(&info->palette[readcolors * 3], &web_palette[readcolors * 3],
- sizeof(web_palette) - readcolors * 3);
- else
- for (i = readcolors; i < 256; i++)
- {
- info->palette[3 * i + 0] = i;
- info->palette[3 * i + 1] = i;
- info->palette[3 * i + 2] = i;
- }
- }
- else if (info->bitcount == 4)
- {
- if (!bmp_palette_is_gray(ctx, info, readcolors))
- memcpy(&info->palette[readcolors * 3], &vga_palette[readcolors * 3],
- sizeof(vga_palette) - readcolors * 3);
- else
- for (i = readcolors; i < 16; i++)
- {
- info->palette[3 * i + 0] = (i << 4) | i;
- info->palette[3 * i + 1] = (i << 4) | i;
- info->palette[3 * i + 2] = (i << 4) | i;
- }
- }
- else if (info->bitcount == 2)
- memcpy(info->palette, gray_palette, sizeof(gray_palette));
- else if (info->bitcount == 1)
- memcpy(info->palette, bw_palette, sizeof(bw_palette));
- }
- static const unsigned char *
- bmp_read_palette(fz_context *ctx, struct info *info, const unsigned char *begin, const unsigned char *end, const unsigned char *p)
- {
- int i, expected, present, entry_size;
- entry_size = palette_entry_size(info);
- if (info->colors == 0)
- expected = info->colors = 1 << info->bitcount;
- else
- expected = fz_mini(info->colors, 1 << info->bitcount);
- if (info->bitmapoffset == 0)
- present = fz_mini(expected, (end - p) / entry_size);
- else
- present = fz_mini(expected, (begin + info->bitmapoffset - p) / entry_size);
- for (i = 0; i < present; i++)
- {
- /* ignore alpha channel even if present */
- info->palette[3 * i + 0] = read8(p + i * entry_size + 2);
- info->palette[3 * i + 1] = read8(p + i * entry_size + 1);
- info->palette[3 * i + 2] = read8(p + i * entry_size + 0);
- }
- if (present < expected)
- bmp_load_default_palette(ctx, info, present);
- return p + present * entry_size;
- }
- static const unsigned char *
- bmp_read_info_header(fz_context *ctx, struct info *info, const unsigned char *begin, const unsigned char *end, const unsigned char *p)
- {
- uint32_t size;
- if (end - p < 4)
- fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in info header in bmp image");
- size = info->version = read32(p + 0);
- if (!is_win_bmp(info) && !is_os2_bmp(info))
- fz_throw(ctx, FZ_ERROR_FORMAT, "unknown header version (%u) in bmp image", info->version);
- if ((uint32_t)(end - p) < size)
- fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in info header in bmp image");
- /* default compression */
- info->compression = BI_NONE;
- /* OS/2 1.x or Windows v2 */
- if (size == 12)
- {
- /* read32(p+0) == header size */
- info->width = read16(p + 4);
- info->height = read16(p + 6);
- /* read16(p+8) == planes */
- info->bitcount = read16(p + 10);
- }
- /* OS/2 2.x short header */
- if (size >= 16)
- {
- /* read32(p+0) == header size */
- info->width = read32(p + 4);
- info->height = read32(p + 8);
- /* read16(p+12) == planes */
- info->bitcount = read16(p + 14);
- }
- /* default masks */
- if (info->bitcount == 16)
- {
- info->rmask = 0x00007c00;
- info->gmask = 0x000003e0;
- info->bmask = 0x0000001f;
- info->amask = 0x00000000;
- }
- else if (info->bitcount == 24 || info->bitcount == 32)
- {
- info->rmask = 0x00ff0000;
- info->gmask = 0x0000ff00;
- info->bmask = 0x000000ff;
- info->amask = 0x00000000;
- }
- /* Windows v3 header */
- if (size >= 40)
- {
- info->compression = read32(p + 16);
- info->bitmapsize = read32(p + 20);
- info->xres = read32(p + 24);
- info->yres = read32(p + 28);
- info->colors = read32(p + 32);
- if (info->bitcount >= 32)
- {
- if (info->colors != 0)
- fz_warn(ctx, "Suspect BMP header; bitcount=%d, colors=%d", info->bitcount, info->colors);
- info->colors = 0;
- }
- else if (info->colors > (1U<<info->bitcount))
- {
- fz_warn(ctx, "Suspect BMP header; bitcount=%d, colors=%d", info->bitcount, info->colors);
- info->colors = 1<<info->bitcount;
- }
- /* read32(p+36) == important colors */
- }
- /* Windows v3 header with RGB masks */
- if (size == 52 || size == 56 || size == 108 || size == 124)
- {
- info->rmask = read32(p + 40);
- info->gmask = read32(p + 44);
- info->bmask = read32(p + 48);
- }
- /* Windows v3 header with RGBA masks */
- if (size == 56 || size == 108 || size == 124)
- {
- info->amask = read32(p + 52);
- }
- /* OS/2 2.x long header */
- if (size == 64)
- {
- /* read16(p+40) == units */
- /* read16(p+42) == reserved */
- /* read16(p+44) == recording */
- /* read16(p+46) == rendering */
- /* read32(p+48) == size1 */
- /* read32(p+52) == size2 */
- /* read32(p+56) == color encoding */
- /* read32(p+60) == identifier */
- }
- /* Windows v4 header */
- if (size >= 108)
- {
- info->colorspacetype = read32(p + 56);
- info->endpoints[0] = read32(p + 60);
- info->endpoints[1] = read32(p + 64);
- info->endpoints[2] = read32(p + 68);
- info->endpoints[3] = read32(p + 72);
- info->endpoints[4] = read32(p + 76);
- info->endpoints[5] = read32(p + 80);
- info->endpoints[6] = read32(p + 84);
- info->endpoints[7] = read32(p + 88);
- info->endpoints[8] = read32(p + 92);
- info->gamma[0] = read32(p + 96);
- info->gamma[1] = read32(p + 100);
- info->gamma[2] = read32(p + 104);
- }
- /* Windows v5 header */
- if (size >= 124)
- {
- info->intent = read32(p + 108);
- info->profileoffset = read32(p + 112);
- info->profilesize = read32(p + 116);
- /* read32(p+120) == reserved */
- }
- return p + size;
- }
- static fz_pixmap *
- bmp_read_image(fz_context *ctx, struct info *info, const unsigned char *begin, const unsigned char *end, const unsigned char *p, int only_metadata)
- {
- const unsigned char *profilebegin;
- memset(info, 0x00, sizeof (*info));
- info->colorspacetype = 0xffffffff;
- p = profilebegin = bmp_read_file_header(ctx, info, begin, end, p);
- p = bmp_read_info_header(ctx, info, begin, end, p);
- /* clamp bitmap offset to buffer size */
- if (info->bitmapoffset < (uint32_t)(p - begin))
- info->bitmapoffset = (uint32_t)(p - begin);
- if ((uint32_t)(end - begin) < info->bitmapoffset)
- info->bitmapoffset = end - begin;
- if (has_palette(info))
- p = bmp_read_palette(ctx, info, begin, end, p);
- if (has_color_masks(info))
- p = bmp_read_color_masks(ctx, info, begin, end, p);
- info->xres = DPM_TO_DPI(info->xres);
- info->yres = DPM_TO_DPI(info->yres);
- /* extract topdown/bottomup from height for windows bitmaps */
- if (is_win_bmp(info))
- {
- int bits = info->version == 12 ? 16 : 32;
- info->topdown = (info->height >> (bits - 1)) & 1;
- if (info->topdown)
- {
- info->height--;
- info->height = ~info->height;
- info->height &= bits == 16 ? 0xffff : 0xffffffff;
- }
- }
- /* GIMP incorrectly writes BMP v5 headers that omit color masks
- but include colorspace information. This means they look like
- BMP v4 headers and that we interpret the colorspace information
- partially as color mask data, partially as colorspace information.
- Let's work around this... */
- if (info->version == 108 &&
- info->rmask == 0x73524742 && /* colorspacetype */
- info->gmask == 0x00000000 && /* endpoints[0] */
- info->bmask == 0x00000000 && /* endpoints[1] */
- info->amask == 0x00000000 && /* endpoints[2] */
- info->colorspacetype == 0x00000000 && /* endpoints[3] */
- info->endpoints[0] == 0x00000000 && /* endpoints[4] */
- info->endpoints[1] == 0x00000000 && /* endpoints[5] */
- info->endpoints[2] == 0x00000000 && /* endpoints[6] */
- info->endpoints[3] == 0x00000000 && /* endpoints[7] */
- info->endpoints[4] == 0x00000000 && /* endpoints[8] */
- info->endpoints[5] == 0x00000000 && /* gamma[0] */
- info->endpoints[6] == 0x00000000 && /* gamma[1] */
- info->endpoints[7] == 0x00000000 && /* gamma[2] */
- info->endpoints[8] == 0x00000002) /* intent */
- {
- info->rmask = 0;
- /* default masks */
- if (info->bitcount == 16)
- {
- info->rmask = 0x00007c00;
- info->gmask = 0x000003e0;
- info->bmask = 0x0000001f;
- info->amask = 0x00000000;
- }
- else if (info->bitcount >= 24)
- {
- info->rmask = 0x00ff0000;
- info->gmask = 0x0000ff00;
- info->bmask = 0x000000ff;
- info->amask = 0x00000000;
- }
- info->colorspacetype = 0x73524742;
- info->intent = 0x00000002;
- }
- /* get number of bits per component and component shift */
- compute_mask_info(info->rmask, &info->rshift, &info->rbits);
- compute_mask_info(info->gmask, &info->gshift, &info->gbits);
- compute_mask_info(info->bmask, &info->bshift, &info->bbits);
- compute_mask_info(info->amask, &info->ashift, &info->abits);
- #ifdef BMP_DEBUG
- {
- #define chr(c) (((c) >= ' ' && (c) <= '~') ? (c) : '?')
- fz_warn(ctx, "type = %02x%02x %c%c", info->type[0], info->type[1], chr(info->type[0]), chr(info->type[1]));
- if (is_bitmap_array(info->type)) fz_warn(ctx, "\tbitmap array");
- if (is_bitmap(info->type)) fz_warn(ctx, "\tbitmap");
- fz_warn(ctx, "version = %zu", (size_t) info->version);
- if (is_os2_bmp(info)) fz_warn(ctx, "OS/2 bmp");
- if (is_win_bmp(info)) fz_warn(ctx, "Windows bmp");
- fz_warn(ctx, "bitmapoffset = %zu", (size_t) info->bitmapoffset);
- fz_warn(ctx, "width = %zu", (size_t) info->width);
- fz_warn(ctx, "height = %zu", (size_t) info->height);
- fz_warn(ctx, "bitcount = %zu", (size_t) info->bitcount);
- fz_warn(ctx, "compression = %zu", (size_t) info->compression);
- if (info->compression == BI_NONE) fz_warn(ctx, "\tNone");
- if (info->compression == BI_RLE8) fz_warn(ctx, "\tRLE 8");
- if (info->compression == BI_RLE4) fz_warn(ctx, "\tRLE 4");
- if (is_valid_win_compression(info) && info->compression == BI_BITFIELDS) fz_warn(ctx, "\tBITFIELDS");
- if (is_valid_os2_compression(info) && info->compression == BI_HUFFMAN1D) fz_warn(ctx, "\tHUFFMAN1D");
- if (info->compression == BI_JPEG) fz_warn(ctx, "\tJPEG");
- if (info->compression == BI_RLE24) fz_warn(ctx, "\tRLE24");
- if (info->compression == BI_PNG) fz_warn(ctx, "\tPNG");
- if (info->compression == BI_ALPHABITS) fz_warn(ctx, "\tALPHABITS");
- fz_warn(ctx, "bitmapsize = %zu", (size_t) info->bitmapsize);
- fz_warn(ctx, "xres = %zu", (size_t) info->xres);
- fz_warn(ctx, "yres = %zu", (size_t) info->yres);
- fz_warn(ctx, "colors = %zu", (size_t) info->colors);
- fz_warn(ctx, "rmask = 0x%08zx rshift = %d rbits = %d", (size_t) info->rmask, info->rshift, info->rbits);
- fz_warn(ctx, "gmask = 0x%08zx gshift = %d gbits = %d", (size_t) info->gmask, info->gshift, info->gbits);
- fz_warn(ctx, "bmask = 0x%08zx bshift = %d bbits = %d", (size_t) info->bmask, info->bshift, info->bbits);
- fz_warn(ctx, "amask = 0x%08zx ashift = %d abits = %d", (size_t) info->amask, info->ashift, info->abits);
- fz_warn(ctx, "colorspacetype = %08zx %c%c%c%c", (size_t) info->colorspacetype,
- chr((info->colorspacetype >> 24) & 0xff),
- chr((info->colorspacetype >> 16) & 0xff),
- chr((info->colorspacetype >> 8) & 0xff),
- chr((info->colorspacetype >> 0) & 0xff));
- fz_warn(ctx, "endpoints[%d] = 0x%08zx 0x%08zx 0x%08zx", 0, (size_t) info->endpoints[0], (size_t) info->endpoints[1], (size_t) info->endpoints[2]);
- fz_warn(ctx, "endpoints[%d] = 0x%08zx 0x%08zx 0x%08zx", 3, (size_t) info->endpoints[3], (size_t) info->endpoints[4], (size_t) info->endpoints[5]);
- fz_warn(ctx, "endpoints[%d] = 0x%08zx 0x%08zx 0x%08zx", 6, (size_t) info->endpoints[6], (size_t) info->endpoints[7], (size_t) info->endpoints[8]);
- fz_warn(ctx, "gamma = 0x%08zx 0x%08zx 0x%08zx", (size_t) info->gamma[0], (size_t) info->gamma[1], (size_t) info->gamma[2]);
- fz_warn(ctx, "profileoffset = %zu", (size_t) info->profileoffset);
- fz_warn(ctx, "profilesize = %zu", (size_t) info->profilesize);
- #undef chr
- }
- #endif
- if (info->width == 0 || info->width > SHRT_MAX || info->height == 0 || info->height > SHRT_MAX)
- fz_throw(ctx, FZ_ERROR_LIMIT, "image dimensions (%u x %u) out of range in bmp image", info->width, info->height);
- if (!is_valid_compression(info))
- fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported compression method (%u) in bmp image", info->compression);
- if (!is_valid_bitcount(info))
- fz_throw(ctx, FZ_ERROR_FORMAT, "invalid bits per pixel (%u) for compression (%u) in bmp image", info->bitcount, info->compression);
- if (info->rbits > info->bitcount)
- fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported %u bit red mask in bmp image", info->rbits);
- if (info->gbits > info->bitcount)
- fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported %u bit green mask in bmp image", info->gbits);
- if (info->bbits > info->bitcount)
- fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported %u bit blue mask in bmp image", info->bbits);
- if (info->abits > info->bitcount)
- fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported %u bit alpha mask in bmp image", info->abits);
- /* Read color profile or default to RGB */
- if (has_color_profile(info))
- info->cs = bmp_read_color_profile(ctx, info, profilebegin, end);
- if (!info->cs)
- info->cs = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
- if (only_metadata)
- return NULL;
- /* bitmap cannot begin before headers have ended */
- if ((uint32_t)(p - begin) < info->bitmapoffset)
- p = begin + info->bitmapoffset;
- if (is_win_bmp(info) && info->compression == BI_JPEG)
- {
- if ((uint32_t)(end - p) < info->bitmapsize)
- fz_warn(ctx, "premature end in jpeg image embedded in bmp image");
- return fz_load_jpeg(ctx, p, end - p);
- }
- else if (is_win_bmp(info) && info->compression == BI_PNG)
- {
- if ((uint32_t)(end - p) < info->bitmapsize)
- fz_warn(ctx, "premature end in png image embedded in bmp image");
- return fz_load_png(ctx, p, end - p);
- }
- else
- return bmp_read_bitmap(ctx, info, begin, end, p);
- }
- fz_pixmap *
- fz_load_bmp_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int subimage)
- {
- const unsigned char *begin = buf;
- const unsigned char *end = buf + len;
- const unsigned char *p = begin;
- struct info info = { 0 };
- int nextoffset = 0;
- fz_pixmap *image = NULL;
- int origidx = subimage;
- (void) p;
- do
- {
- p = begin + nextoffset;
- if (end - p < 14)
- fz_throw(ctx, FZ_ERROR_FORMAT, "not enough data for bitmap array (%02x%02x) in bmp image", p[0], p[1]);
- if (is_bitmap_array(p))
- {
- /* read16(p+0) == type */
- /* read32(p+2) == size of this header in bytes */
- nextoffset = read32(p + 6);
- /* read16(p+10) == suitable pelx dimensions */
- /* read16(p+12) == suitable pely dimensions */
- p += 14;
- (void) p;
- }
- else if (is_bitmap(p))
- {
- nextoffset = 0;
- }
- else
- {
- fz_warn(ctx, "treating invalid subimage as end of file");
- nextoffset = 0;
- }
- if (end - begin < nextoffset)
- {
- fz_warn(ctx, "treating invalid next subimage offset as end of file");
- nextoffset = 0;
- }
- else
- subimage--;
- } while (subimage >= 0 && nextoffset > 0);
- if (subimage != -1)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "subimage index (%d) out of range in bmp image", origidx);
- fz_try(ctx)
- image = bmp_read_image(ctx, &info, begin, end, p, 0);
- fz_always(ctx)
- fz_drop_colorspace(ctx, info.cs);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return image;
- }
- void
- fz_load_bmp_info_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep, int subimage)
- {
- const unsigned char *begin = buf;
- const unsigned char *end = buf + len;
- const unsigned char *p = begin;
- struct info info = { 0 };
- int nextoffset = 0;
- int origidx = subimage;
- (void) p;
- do
- {
- p = begin + nextoffset;
- if (end - p < 14)
- fz_throw(ctx, FZ_ERROR_FORMAT, "not enough data for bitmap array (%02x%02x) in bmp image", p[0], p[1]);
- if (is_bitmap_array(p))
- {
- /* read16(p+0) == type */
- /* read32(p+2) == size of this header in bytes */
- nextoffset = read32(p + 6);
- /* read16(p+10) == suitable pelx dimensions */
- /* read16(p+12) == suitable pely dimensions */
- p += 14;
- (void) p;
- }
- else if (is_bitmap(p))
- {
- nextoffset = 0;
- }
- else
- {
- fz_warn(ctx, "treating invalid subimage as end of file");
- nextoffset = 0;
- }
- if (end - begin < nextoffset)
- {
- fz_warn(ctx, "treating invalid next subimage offset as end of file");
- nextoffset = 0;
- }
- else
- subimage--;
- } while (subimage >= 0 && nextoffset > 0);
- if (subimage != -1)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "subimage index (%d) out of range in bmp image", origidx);
- fz_try(ctx)
- {
- (void) bmp_read_image(ctx, &info, begin, end, p, 1);
- *cspacep = fz_keep_colorspace(ctx, info.cs);
- *wp = info.width;
- *hp = info.height;
- *xresp = info.xres;
- *yresp = info.yres;
- }
- fz_always(ctx)
- fz_drop_colorspace(ctx, info.cs);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- int
- fz_load_bmp_subimage_count(fz_context *ctx, const unsigned char *buf, size_t len)
- {
- const unsigned char *begin = buf;
- const unsigned char *end = buf + len;
- uint32_t nextoffset = 0;
- int count = 0;
- do
- {
- const unsigned char *p = begin + nextoffset;
- if (end - p < 14)
- fz_throw(ctx, FZ_ERROR_FORMAT, "not enough data for bitmap array in bmp image");
- if (is_bitmap_array(p))
- {
- /* read16(p+0) == type */
- /* read32(p+2) == size of this header in bytes */
- nextoffset = read32(p + 6);
- /* read16(p+10) == suitable pelx dimensions */
- /* read16(p+12) == suitable pely dimensions */
- p += 14;
- }
- else if (is_bitmap(p))
- {
- nextoffset = 0;
- }
- else
- {
- fz_warn(ctx, "treating invalid subimage as end of file");
- nextoffset = 0;
- }
- if (end - begin < nextoffset)
- {
- fz_warn(ctx, "treating invalid next subimage offset as end of file");
- nextoffset = 0;
- }
- else
- count++;
- } while (nextoffset > 0);
- return count;
- }
- fz_pixmap *
- fz_load_bmp(fz_context *ctx, const unsigned char *p, size_t total)
- {
- return fz_load_bmp_subimage(ctx, p, total, 0);
- }
- void
- fz_load_bmp_info(fz_context *ctx, const unsigned char *p, size_t total, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep)
- {
- fz_load_bmp_info_subimage(ctx, p, total, wp, hp, xresp, yresp, cspacep, 0);
- }
|